Archive for October, 2010

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