observer Спостерігач (англ. Observer) створює механізм передплати, за допомогою якого одні об’єкти можуть підписуватись на оновлення, що відбуваються в інших об’єктах під час виконання програми. Як тільки об’єкт, що спостерігається, змінюється, він сповіщає всіх своїх слухачів, щоб вони змогли зреагувати на цю зміну.

Для реалізації публікації/підписки на поведінку об’єкта щоразу, коли об’єкт Subject змінює свій стан, прикріплені об’єкти Observers сповіщаються. Шаблон використовується, щоб скоротити кількість пов’язаних безпосередньо об’єктів, і замість цього використовує слабкий зв’язок (loose coupling).

PHP надає два стандартні інтерфейси, які можуть допомогти реалізувати цей шаблон: SplObserver та SplSubject.

  • Newspaper.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Observer;
    
    use SplObserver;
    use SplSubject;
    
    /**
     * Class Newspaper
     * @package DesignPatterns\Behavioral\Observer
     */
    class Newspaper implements SplSubject
    {
        /**
         * @var string
         */
        protected $name;
    
        /**
         * @var SplObserver[]
         */
        protected $observers = [];
    
        /**
         * @var string
         */
        protected $content;
    
        /**
         * Newspaper constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @param SplObserver $observer
         *
         * @return void
         */
        public function attach(SplObserver $observer)
        {
            array_push($this->observers, $observer);
        }
    
        /**
         * @param SplObserver $observer
         *
         * @return void
         */
        public function detach(SplObserver $observer)
        {
            $key = array_search($observer, $this->observers, true);
            if ($key) {
                unset($this->observers[$key]);
            }
        }
    
        /**
         * @param $content
         *
         * @return void
         */
        public function breakOutNews($content)
        {
            $this->content = $content;
            $this->notify();
        }
    
        /**
         * @return string
         */
        public function getContent(): string
        {
            return $this->content . '( ' . $this->name . ' )';
        }
    
        /**
         * @return void
         */
        public function notify()
        {
            foreach ($this->observers as $value) {
                $value->update($this);
            }
        }
    }
    
                  
  • Reader.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Observer;
    
    use SplObserver;
    use SplSubject;
    
    /**
     * Class Reader
     * @package DesignPatterns\Behavioral\Observer
     */
    class Reader implements SplObserver
    {
        /**
         * @var string
         */
        protected $name;
    
        /**
         * Reader constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @param SplSubject|Newspaper $subject
         */
        public function update(SplSubject $subject)
        {
            echo $this->name . ' is reading breakout news ' . $subject->getContent();
        }
    }
    
                  
  • Test case:

    ObserverTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Behavioral\Observer;
    
    use DesignPatterns\Behavioral\Observer\Newspaper;
    use DesignPatterns\Behavioral\Observer\Reader;
    use PHPUnit_Framework_TestCase;
    
    class ObserverTest extends PHPUnit_Framework_TestCase
    {
        public function testPostedNewsAndUserNotify()
        {
            $newspaper = new Newspaper('New York Times');
            $allen = new Reader('Allen');
    
            $newspaper->attach($allen);
            $newspaper->breakOutNews('Good news!');
    
            $this->expectOutputString('Allen is reading breakout news Good news!( New York Times )');
        }
    }