Making Sense of the Observer with Me
Until today I’ve struggled to see how the observer might be useful and why it can’t be done using something similar to the plugin system I blogged about last week.
After a little discussion over at DevNetwork Forums I’ve come to see that the observer does have it’s place in PHP, although it’s rare you’ll ever need it. There’s not much (at least not much variation) written about this pattern online so here’s my shot at it.
Take a system that runs methods which may or may not execute correctly (think, DB object with connection failure). You might not want your system to churn out errors when something didn’t work. You may be happy enough just having a boolean FALSE returned.
Now imagine you want to re-use that object in another system. This time you need some sort of prettied up visual notification to provide the end user when something went wrong. You need some way of know when the system errors and what the error is. Here’s where the observer might be handy.
You might then want to use that same code in yet another project, this time you need to keep a log of all errors in a database so you can analyse them statistically. It’s getting messy if we don’t use something flexible.
Let’s take a look.
Here our Observable can hold various types of observers - this is purely for flexibility and organisation. The type we’ll be holding here is of type “ERROR”. The observable needs to be able to tell any observers when to do something. We use a method called notify() here to do this.
We have three classes. One is the observer (errorHandler), one is the observable (someClass) and the other is just a container of type ‘ERROR’.
When the observable produces an error it notifies any observers by passing them a new error message object which contains the error. It’s then up to the observer what to do with it (log it to db, write it to flat file, parse it into a smarty template, trigger_error()….). Here we simply echo it to the page. The observable doesn’t care either way.
//Just describes what methods the errorMsg object should hold
interface iErrorMsg
{
public function __construct($string);
public function getErrorString();
}
//Simple, any observers need a notify method so they know when
// to run. That’s all
interface iObserver
{
public function notify($object);
}
//The observable
class someClass
{
//Observers container
private $observers = array();
//Load an observer object of type $type
public function registerObserver(iObserver $observer, $type)
{
//Make a new container for $type in the observers container if needed
if (!isset($this->observers[$type])) $this->observers[$type] = array();
//Load the observer into the container
$this->observers[$type][] = $observer;
}
//Looks for observers of the correct type and runs the notify()
// method in all of them
private function notify($object)
{
if (isset($this->observers[$object->getType()]))
{
foreach ($this->observers[$object->getType()] as $i => $obj)
{
$this->observers[$object->getType()][$i]->notify($object);
}
}
}
public function someMethodThatCanError()
{
if (/*something went wrong*/)
{
//We pass notify an instance of the error message
$this->notify(new errorMsg(‘Oops, something went wrong’));
return false;
}
else //just do something and return TRUE
}
}
//Just a container in essence. Holds information for the observers to use
class errorMsg implements iErrorMsg
{
private $errorString;
public function __construct($error_string)
{
$this->errorString = $error_string;
}
//The observers use this type
public function getType()
{
return ‘ERROR’;
}
public function getErrorString()
{
return $this->errorString;
}
}
//Our observer
class errorHandler implements iObserver
{
//This is called from the observable’s notify() method
// and $object should be of type ERROR
public function notify($object)
{
if ($object instanceof errorMsg)
{
echo $object->getErrorString();
}
}
}
$someObject = new someClass;
//Load the observer as an ERROR type
$someObject->registerObserver(new errorHandler, errorMsg::getType());
//If there’s an error the observer should display it via notify()
$someObject->someMethodThatCanError();
?>
A sort of practical example. But as you can see, it’s still not really best implemented in PHP.
No Responses to “Making Sense of the Observer with Me”
No comments yet