The Observer Pattern is designed to help cope with one to many relationships between objects, allowing changes in an object to update many associated objects. It provides a powerful mechanism to extend our applications, in terms of how they respond to events, without needing alter existing (and working) code.

We’ll take a simplified look at how the observer pattern might be used in a typical PHP forum application then suggest other uses for the observer pattern

Under Observation

1) The Observer pattern is defined by the Gang of Four in Design Patterns as behavioural pattern - that is one we can use to modify the behaviour of our applications. It’s regarded as being so useful, that Sun bothered to implement it in the Java API (see Observable and Observer).

The basic principle behind the observer pattern is if you have some object, such as a Post object for a forum system, you can have other objects, such as a Mailer object, act as an observer and respond to any changes in the Post object, such as emailing relevant forums users that a new post has been added to the thread they were subscribed to.

Conceptually, the Observer pattern in something like a trigger in a database, which runs a stored procedure when a table row is modified for example (we won’t go too far with this analogy though).

Normally we might implement the mailing functionality in the Post object itself but what if later we want add further “events” to Post, when a new post is made, such as adding an entry to our forums RSS feed for example? And how many more things might we want to add in future?

The observer pattern provides us the mechanism to add such functionality without needing to alter the Post object.

The is easiest to see will some some example code.

First we define two interface classes; an Observable class which will be inherited by the Post class and allows it to become the subject of observation and an Observer class which will be inherited by the classes used to observer Post.

<?php
/**
 *  Base Observerable class
 */
class Observable {
    /**
    * Private
    * $observers an array of Observer objects to notify
    */
    var $observers;
 
    /**
    * Private
    * $state store the state of this observable object
    */
    var $state;
 
    //! A constructor
    /**
    * Constructs the Observerable object
    */
    function Observable () {
        $this->observers=array();
    }
 
    //! An accessor
    /**
    * Calls the update() function using the reference to each
    * registered observer - used by children of Observable
    * @return void
    */ 
    function notifyObservers () {
        $observers=count($this->observers);
        for ($i=0;$i<$observers;$i++) {
            $this->observers[$i]->update();
        }
    }
 
    //! An accessor
    /**
    * Register the reference to an object object
    * @return void
    */ 
    function addObserver (& $observer) {
        $this->observers[]=& $observer;
    }
 
    //! An accessor
    /**
    * Returns the current value of the state property
    * @return mixed
    */ 
    function getState () {
        return $this->state;
    }
 
    //! An accessor
    /**
    * Assigns a value to state property
    * @param $state mixed variable to store
    * @return void
    */ 
    function setState ($state) {
        $this->state=$state;
    }
}
?>

And

<?php
/**
 *  Base Observer class
 */
class Observer {
    /**
    * Private
    * $subject a child of class Observable that we're observing
    */
    var $subject;
 
    //! A constructor
    /**
    * Constructs the Observer
    * @param $subject the object to observe
    */
    function Observer (& $subject) {
        $this->subject=& $subject;
 
        // Register this object so subject can notify it
        $subject->addObserver($this);
    }
 
    //! An accessor
    /**
    * Abstract function implemented by children to repond to
    * to changes in Observable subject
    * @return void
    */    
    function update() {
        trigger_error ('Update not implemented');
    }
}
?>

Notice in the construction of Observer, it is passed a reference to an instance of Observable then calls the addObserver() method in Observable to register itself as a “watching” object.

Note we’ve taken only one of a number possible approaches to “relating” the subject observable classes and watching observer classes (more on this in a moment).

Now we have those, we can extend the Observable class with Post (note we’re only going to simulate these classes here - writing an entire forum application for this demonstration is a little more than time allows...);

<?php
/**
 *  Class which simulates a forum Post
 */
class Post extends Observable {
 
    //! A constructor
    /**
    * Constructs the Post
    */
    function Post () {
        Observable::Observable();
    }
 
    //! An accessor
    /**
    * Simulates the adding of a forum post and notifies observers
    * @return void
    */
    function addPost () {
        echo ( '$post->addPost(): Dummy post added<br />' );
 
        // Set the state
        $this->setState('Post added');
 
        // Call the parent function to notify all observers
        $this->notifyObservers();
    }
}
?>

Notice how the addPost() method calls it’s parent notifyObservers() method. This means that when a post is added, all observers will be notified of the change and can react appropriately. Apart from that, we’ve said nothing about what will be observing the Post object when instantiated. Post knows nothing (and doesn’t care) about the objects observing it.

Now we define a class Mailer which will inherit from the from Observer class;

<?php
/**
 *  Class which simulates send email to users subscribed to
 *  a forum thread
 */
class Mailer extends Observer {
 
    //! A constructor
    /**
    * Constructs the Mailer object passing the parent
    * the subject observable object
    */
    function Mailer (& $post) {
        Observer::Observer($post);
    }
 
    //! An accessor
    /**
    * Implement the parent update() method checking the state
    * of the observable subject
    * @return void
    */
    function update () {
        if ( $this->subject->getState() == 'Post added' ) {
            $this->sendMail();
        }
    }
 
    //! An accessor
    /**
    * Simulates the sending of email to all users subscribed to the
    * thread
    * @return void
    */
    function sendMail () {
        echo ( '$mailer->sendMail(): Sending mail to all users subscribed '
               .'to this thread<br />' );
        // mail () etc...
    }
}
?>

We’ve defined a method update() here which all children of Observer must have (as it will be used by the Observable class when performing the notifyObservers() method). The update() method checks the state of the subject observable class and decides what it should do.

Now, to demonstrate the point, we’ll define a second observer called Feed, which simulates updating the XML file used to publish an RSS feed for our site.

<?php
/**
 *  Class which simulates adding a new entry to an RSS feed
 */
class Feed extends Observer {
 
    //! A constructor
    /**
    * Constructs the Feed object passing the parent
    * the subject observable object
    */
    function Feed (& $thread) {
        Observer::Observer($thread);
    }
 
    //! An accessor
    /**
    * Implement the parent update() method checking the state
    * of the observable subject
    * @return void
    */
    function update () {
        if ( $this->subject->getState() == 'Post added' ) {
            $this->updateFeed();
        }
    }
 
    //! An accessor
    /**
    * Simulates the updating of the RSS feed
    * @return void
    */
    function updateFeed () {
        echo ( '$feed->updateFeed(): Updating RSS feed<br />' );
        // Edit XML file...
    }
}
?>

In UML terms this looks something like;

Note that the above diagram isn’t strictly correct as the Observable and Observer classes are related by association - the diagram is intended to show how the Observable pattern notifies the the Observers.

Now lets see how these classes might be put into action;

<?php
require_once('lib/Observable.php');
require_once('lib/Observer.php');
require_once('lib/Post.php');
require_once('lib/Mailer.php');
require_once('lib/Feed.php');

// Construct observable subject
$post=new Post;

// Construct observers
$mailer=new Mailer($post);
$feed=new Feed($post);
?>
<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> Observer Pattern Demo </title>
</head>
<body>

<?php
// Calling the addPost method triggers the observers to respond
$post->addPost();
?>

</body>
</html>

Notice how we only call the addPost() method from the instance of Post. The HTML output looks something like this;

$post->addPost(): Dummy post added
$mailer->sendMail(): Sending mail to all users subscribed to this thread
$feed->updateFeed(): Updating RSS feed

The instances Mailer and Feed automatically respond to the the event of adding a post! When they were instantiated, Mailer and Feed “registered” themselves with the instance of Post, basically saying “let me know of any changes”. When the addPost() method was called, Post simply notified Mailer and Feed that a change had occurred and left it to them to decided whether they needed to react.

What’s more, depending on how we design the observer classes, we could reuse them with other observable objects.

The observer pattern can be readily applied to many common PHP problems. Some examples;

- Building a user registration system, where we might add observers for sending registration emails, checking the user’s email MX record as valid and so on (this example is used in Design Patterns Explains using Java as a the reference language).

- “Watching” updates made to a Log file, as in PEAR::Log which is discussed in this presentation - the approach taken in PEAR for constructing an observer pattern is somewhat different to the one we’ve used here, using Singleton and Factory method patterns.

- As a tool for performing multiple INSERTs / UPDATEs to a database (which can come in handy for a database like MySQL, where triggers are not supported).

Note that if we want to avoid having to modify the subject class (Post in our example) or the observer classes, to inherit from the base classes, we can use the Adapter pattern.

Further Reading


design/observer_pattern.txt · Last modified: 2005/10/15 21:47