1. <?php
    2. //spl standard php library
    3. /**
    4. * PHP has a couple of built-in interfaces related to the Observer pattern.
    5. *
    6. * Here's what the Subject interface looks like:
    7. *
    8. * @link http://php.net/manual/en/class.splsubject.php
    9. *
    10. * interface SplSubject
    11. * {
    12. * // Attach an observer to the subject.
    13. * public function attach(SplObserver $observer);
    14. *
    15. * // Detach an observer from the subject.
    16. * public function detach(SplObserver $observer);
    17. *
    18. * // Notify all observers about an event.
    19. * public function notify();
    20. * }
    21. *
    22. * There's also a built-in interface for Observers:
    23. *
    24. * @link http://php.net/manual/en/class.splobserver.php
    25. *
    26. * interface SplObserver
    27. * {
    28. * public function update(SplSubject $subject);
    29. * }
    30. */
    31. /**
    32. * The Subject owns some important state and notifies observers when the state
    33. * changes.
    34. */
    35. class Subject implements \SplSubject
    36. {
    37. /**
    38. * @var int For the sake of simplicity, the Subject's state, essential to
    39. * all subscribers, is stored in this variable.
    40. */
    41. public $state;
    42. /**
    43. * @var \SplObjectStorage List of subscribers. In real life, the list of
    44. * subscribers can be stored more comprehensively (categorized by event
    45. * type, etc.).
    46. */
    47. private $observers;
    48. public function __construct()
    49. {
    50. $this->observers = new \SplObjectStorage();
    51. }
    52. /**
    53. * The subscription management methods.
    54. */
    55. public function attach(\SplObserver $observer): void
    56. {
    57. echo "Subject: Attached an observer.\n";
    58. $this->observers->attach($observer);
    59. }
    60. public function detach(\SplObserver $observer): void
    61. {
    62. $this->observers->detach($observer);
    63. echo "Subject: Detached an observer.\n";
    64. }
    65. /**
    66. * Trigger an update in each subscriber.
    67. */
    68. public function notify(): void
    69. {
    70. echo "Subject: Notifying observers...\n";
    71. foreach ($this->observers as $observer) {
    72. $observer->update($this);
    73. }
    74. }
    75. /**
    76. * Usually, the subscription logic is only a fraction of what a Subject can
    77. * really do. Subjects commonly hold some important business logic, that
    78. * triggers a notification method whenever something important is about to
    79. * happen (or after it).
    80. */
    81. public function someBusinessLogic(): void
    82. {
    83. echo "\nSubject: I'm doing something important.\n";
    84. $this->state = rand(0, 10);
    85. echo "Subject: My state has just changed to: {$this->state}\n";
    86. $this->notify();
    87. }
    88. }
    89. /**
    90. * Concrete Observers react to the updates issued by the Subject they had been
    91. * attached to.
    92. */
    93. class ConcreteObserverA implements \SplObserver
    94. {
    95. public function update(\SplSubject $subject): void
    96. {
    97. if ($subject->state < 3) {
    98. echo "ConcreteObserverA: Reacted to the event.\n";
    99. }
    100. }
    101. }
    102. class ConcreteObserverB implements \SplObserver
    103. {
    104. public function update(\SplSubject $subject): void
    105. {
    106. if ($subject->state == 0 || $subject->state >= 2) {
    107. echo "ConcreteObserverB: Reacted to the event.\n";
    108. }
    109. }
    110. }
    111. /**
    112. * The client code.
    113. */
    114. $subject = new Subject();
    115. $o1 = new ConcreteObserverA();
    116. $subject->attach($o1);
    117. $o2 = new ConcreteObserverB();
    118. $subject->attach($o2);
    119. $subject->someBusinessLogic();
    120. $subject->someBusinessLogic();
    121. $subject->detach($o2);
    122. $subject->someBusinessLogic();

    输出

    1. Subject: Attached an observer.
    2. Subject: Attached an observer.
    3. Subject: I'm doing something important.
    4. Subject: My state has just changed to: 8
    5. Subject: Notifying observers...
    6. ConcreteObserverB: Reacted to the event.
    7. Subject: I'm doing something important.
    8. Subject: My state has just changed to: 0
    9. Subject: Notifying observers...
    10. ConcreteObserverA: Reacted to the event.
    11. ConcreteObserverB: Reacted to the event.
    12. Subject: Detached an observer.
    13. Subject: I'm doing something important.
    14. Subject: My state has just changed to: 1
    15. Subject: Notifying observers...
    16. ConcreteObserverA: Reacted to the event.