Practical example php implementation of the Observer pattern

October 12, 2010

Observer is a pattern where an object called the subject maintains a list of dependents (observers) and notifies them of any state changes. I implemented this recently to log changes to an Account object, and to notify the account holder if their account had expired – here’s the basics of the code, hopefully it’ll help someone else figure out how the pattern works

<?php
interface Observer
{
 public function update(Observable $subject);
} 

interface Observable
{
 public function attachObserver(Observer $dependent);
 public function detachObserver(Observer $dependent);
 public function notify();
}

class Account implements Observable
{
 public $status;
 private $_observers = array();

 public function __construct()
 {
  $this->attachObserver(new Logger());
  $this->attachObserver(new Mailer());
 }

 public function attachObserver(Observer $object)
 {
  $this->_observers[] = $object;
 }

 public function detachObserver(Observer $object)
 {
  foreach ($this->_observers as $index => $observer) {
   if ($object == $observer) {
    unset($this->_observers[$index]);
   }
  }
 }

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

 public function save()
 {
  $this->notify($this);
  $this->notify();
 }
}

class Logger implements Observer
{
 public function update(Observable $subject)
 {
 //Update status in log table
 echo "Updating status in log table.\n";
 }
}

class Mailer implements Observer
{
 public function update(Observable $subject)
 {
 switch (get_class($subject)) {      
 case "Account":
 if ($subject->status == "Expired") {
 //send email: "account expired"
 echo "Sending account expired email.\n";
 }
 }
 }
}

$account = new Account();
$account->status = "Expired";
$account->save();

The interfaces aren’t strictly necessary, but they help make the whole thing clearer (I hope).

$this->notify($this);
About these ads

12 Responses to “Practical example php implementation of the Observer pattern”

  1. kae verens Says:

    nice. I’ve never had to implement it, so never looked at it, but now that I’ve seen it written, I can imagine some uses in my own stuff (for example, watching a file’s status, and calling various plugins if it changes)

    only thing I’d say is to remove the $this parameter from “$this->notify($this);” – that method doesn’t have any parameters in its header, and surely the $this in the method would always be from the same instance anyway?

  2. Jake Smith Says:

    Is there any reason why you chose not to implement SplObserver and SplSubject?

    • cormacscode Says:

      Yes – I didn’t know about them until now :) Will fill those gaps in my knowledge asap


      • Don’t worry – from a design point of view, it doesn’t make any sense to implement patterns in a library like SPL. It would force you to use a particular style of Observer (pull), to not refer to your classes in type hinting, and to implement all methods even if you only need to attach Observers and not to detach them, nor to expose notify().


  3. I always add a method to the subject (Observable) with wich I can get get the current status of it, this because sometimes the subject release several events to the observers, and they need to know if are interested or not in the notification.


  4. Thanks for your explanation. Like Kae, I’ve never had the need to use this pattern, but it’s certainly more clear now :-)

    Regards,
    George

  5. Rune Kaagaard Says:

    Hi

    Thanks for a very interesting post. Just wanted to point in the direction of SplObserver and SplSubject classes that performs similar to your Observer and Observable classes. Had a little fun rewriting your cool little example using those. See http://pastebin.com/ZPHPtA0d. Also notice the use of the ultra usefull SplObjectStorage class.

    Cheers!

  6. eRadical Says:

    Thumbs up from me too. I already have this in a code and a friend programmer did not understood my code… but he understood yours. (Of course I didn’t had time to extract from the project a similar simple example.)

    One small note. In “function detachObserver(Observer $object)”… it would probably be unlikely to have “the same object” registered twice so after “unset…” I would go for a “return;”… what do you think ?

  7. razvantim Says:

    Great and simple example of the Observer pattern. Thanks for this article


  8. Even though i have seen this pattern dozens of times, especially in java, i have never coded it in php :) i think you provided a nice example :)

    The thing i dont like about this pattern is the generic naming … i always forget which method does what (notify / update) as for me they are meaningless. Maybe GOF could come up with something like notifyListeners or handleEvent or something even better. Especially in PHP that does not play nicely as there is no overloading like in Java or C#. You cant have any class implement subject interface because they may have update methods already. If your logger had an update method then you would be in trouble :/

    Its a nice example for PHP though :)

    cheers !


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: