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 )');
        }
    }