Search code examples
phpobserver-patternspl

How is SplSubject/SplObserver useful?


The Standard PHP Library includes what some resources call a reference implementation of the Observer pattern, by way of the SplSubject and SplObserver classes. For the life of me, I can't figure out how these are very useful with no way to pass actual events or any other information along with the notifications:

class MySubject implements SplSubject {
    protected $_observers = [];

    public function attach(SplObserver $observer) {
        $id = spl_object_hash($observer);
        $this->_observers[$id] = $observer;
    }

    public function detach(SplObserver $observer) {
        $id = spl_object_hash($observer);

        if (isset($this->_observers[$id])) {
            unset($this->_observers[$id]);
        }
    }

    public function notify() {
        foreach ($this->_observers as $observer) {
            $observer->update($this);
        }
    }
}

class MyObserver implements SplObserver {
    public function update(SplSubject $subject) {
        // something happened with $subject, but what
        // was it???
    }
}

$subject = new MySubject();
$observer = new MyObserver();

$subject->attach($observer);
$subject->notify();

It seems like these interfaces are pretty much useless for any real world problem. Can someone enlighten me?


Edit:

Here's my biggest problem with the interface (although there are others):

public function update(SplSubject $subject, Event $event) { /* ... */ }

...nets the following fatal error:

PHP Fatal error:  Declaration of MyObserver::update() must be compatible with SplObserver::update(SplSubject $SplSubject)

Edit #2:

Making the additional parameters optional by giving them defaults prevents the fatal error and provides a way to pass context, making implementations worthwhile. I wasn't previously aware of this, so this pretty much answers my question. The solution is to pass your own event/message data, and check for its existance inside SplObserver::update().


Solution

  • You can implement the update method with an optional parameter and still satisfy the SplSubject interface.

    class MyObserver implements SplObserver {
        public function update(SplSubject $subject, $eventData = null) {
            if (is_null($eventData))
                // carefull
        }
    }