Back
Observer
Implementing Observer
Conclusion
Forward


Implementing Observer

The observer pattern is the most complicated to implement of those we'll look at, mainly because it requires a subject class, an observer class, and several methods between them to regulate their interaction.

We'll look at the subject object first. These objects need an attach() method, and a way of notifying observing objects of a state change - we'll call it notifyAll(). For completeness, we'll also include a detach() method. Here is the implementation from PEAR's Log:: package:

<?php
    
/**
     * Adds a Log_observer instance to the list of observers that are be
     * notified when a message is logged.
     *  
     * @param object Log_observer &$logObserver The Log_observer instance to
     *                                          be added to the $listeners
     *                                          array.
     * @access public
     */
    
function attach(&$logObserver)
    {
        if (!
is_object($logObserver)) {
            return 
false;
        }
        
        
$logObserver->_listenerID uniqid(rand());
        
        
$this->_listeners[$logObserver->_listenerID] = &$logObserver;
    }

    
/**
     * Removes a Log_observer instance from the list of observers.
     *
     * @param object Log_observer $logObserver  The Log_observer instance to
     *                                          be removed from the $listeners
     *                                          array.
     * @access public
     */
    
function detach($logObserver)
    {
        if (isset(
$this->_listeners[$logObserver->_listenerID])) {
            unset(
$this->_listeners[$logObserver->_listenerID]);
        }
    }

    
/**
     * Sends any Log_observer objects listening to this Log the message that
     * was just logged.
     *
     * @param array $msgObj     The data structure holding all relevant log
     *                          information - the message, the priority, what
     *                          log this is, etc.
     */
    
function notifyAll($msgObj)
    {
        
reset($this->_listeners);
        foreach (
$this->_listeners as $listener) {
            if (
$msgObj['priority'] <= $listener->priority) {
                
$listener->notify($msgObj);
            }
        }
    }

Since we can't use an object as an array index, we create a unique index when every observer is attached so that we can track them and detach() them transparently to the end user.

The observer side is simpler; we just need to implement the notify() method that we called from the subject in notifyAll() above. We can do whatever we like in it:

<?php
    
/**
     * This is a stub method to make sure that Log_observer classes do
     * something when they are notified of a message. The default
     * behavior is to just print the message, which is obviously not
     * desireable in practically any situation - which is why you need
     * to override this method. :)
     *
     * @param array $messageOb    A hash containing all information - the text
     *                      message itself, the priority, what log it came
     *                      from, etc.
     */
    
function notify($messageOb)
    {
        
print_r($messageOb);
    }