Page 1 of 1
The Observer. I don't get it :(
Posted: Tue Jun 06, 2006 3:56 pm
by Chris Corbyn
I understand the code but I just don't see how it's useful. Maybe this is just a crap example. Could someone enlighten me on a scenario where this might be used?
I'm not even sure is this is a "basic" bare-bones observer or if they've added fluffy bits to show off.
This is from phptr.com:
Code: Select all
<?php
interface Message
{
static function getType();
};
interface Observer
{
function notifyMsg(Message $msg);
};
class Subject
{
private $observers = array();
function registerObserver(Observer $observer, $msgType)
{
$this->observers[$msgType][] = $observer;
}
private function notifyMsg(Message $msg)
{
@$observers = $this->observers[$msg->getType()];
if(!$observers)
{
return;
}
foreach($observers as $observer)
{
$observer->notifyMsg($msg);
}
}
function someMethod()
{
//fake some task
sleep(1);
//notify observers
$this->notifyMsg(new HelloMessage("Zeev"));
}
}
class HelloMessage implements Message
{
private $name;
function __construct($name)
{
$this->name = $name;
}
function getMsg()
{
return "Hello, $this->name!";
}
static function getType()
{
return "HELLO_TYPE";
}
}
class MyObserver implements Observer
{
function notifyMsg(Message $msg)
{
if ($msg instanceof HelloMessage)
{
print $msg->getMsg();
}
}
}
$subject = new Subject();
$observer = new MyObserver();
$subject->registerObserver($observer,
HelloMessage::getType());
$subject->someMethod();
?>
Outputs:
Obviously there's no reason why you can't have multiple observers here, all of which have some "type". The "type" is confusing me. Especially in this example. It looks as though any other loaded observers would execute the notifyMsg() method if they have the same type as "HelloMessage", but then the "Subject" object needs to know the name of at least one observer in this example for anything to happen (or am I missing something?). If that's right this doesn't seem overly flexible.
Can anybody enlighten me on these points?
a) Is this example the basics needed for the observer or have they added frilly bits?
b) Can anyone give a better example or describe a real situation where you'd use this?
Other examples I found online started off with lengthy unit tests which I know nothing about at the moment

Re: The Observer. I don't get it :(
Posted: Tue Jun 06, 2006 4:02 pm
by Chris Corbyn
d11wtq wrote:The "type" is confusing me. Especially in this example. It looks as though any other loaded observers would execute the notifyMsg() method if they have the same type as "HelloMessage", but then the "Subject" object needs to know the name of at least one observer in this example for anything to happen
Ok I'm an idiot. I see it now. I misread where getType() was coming from. That helps a little

I guess I could maybe see a place for this then

Posted: Tue Jun 06, 2006 4:23 pm
by Christopher
I have not used the pattern much, but it is very useful in certain circumstances. I find abstract discussion about it to be pretty worthless as well. A common example of a useful implementation is a spreadsheet where updates to a cell can change other cells, charts/graphs, etc.
Posted: Tue Jun 06, 2006 4:38 pm
by daedalus__
What's an observer?
Posted: Tue Jun 06, 2006 5:18 pm
by timvw
An observer is an object that listens to notifications send by an 'Observable'.
These notifications are send to the Observer through a welldefined 'interface', usually one function 'update(Observable source, ReasonObject reason)'.
I still haven't found a good reason to use this pattern in php code, but in java gui i happen to use it all the time. Eg: i have a splashscreen that observes the 'initalizing application process'... Everytime the loading process advances, it notifies the observers like: notify('now loading sample data into the dataase');... And then the splashscreen recieves this message and changes the text in it's progressbar...
Posted: Tue Jun 06, 2006 5:27 pm
by Chris Corbyn
Daedalus- wrote:What's an observer?
It's an object that responds to events in another object.
In the example above we create an instance of "myObserver" which observes an instance of "Subject". Subject basically triggers the observer to run it's notifyMsg() method at certain points the author of "Subject" has defined; in this case that's when someMethod() runs.
Now, Subject calls all observers by basically going through a loop looking for all observers of the relevant type and executing their notifyMsg() methods. That's why we've got interfaces above.... all observers need a notifyMsg() method.
I guess I'll only really see where it's useful when one day I come across a need for it
See, it's pretty similar (apart from the - seems to me at least - lesser flexibility and absence of types) to:
Code: Select all
class Subject
{
private $pluginCollection = array();
public function loadPlugin($pluginObject, $id)
{
$this->pluginCollection[$id] = $pluginObject;
}
private function triggerEvent($event)
{
$handler = 'on'.$event; //e.g. onConnect
foreach ($this->pluginCollection as $id => $plugin)
{
if (method_exists($plugin, $handler)) $this->pluginCollection[$id]->$handler();
}
}
public function connect($host, $user, $pass)
{
mysql_connect($host, $user, $pass);
$this->triggerEvent('Connect');
}
}
class myPlugin
{
public function onConnect()
{
echo 'Subject has connected!';
}
}
$subject = new Subject;
$subject->loadPlugin(new myPlugin, 'myPlugin');
$subject->connect('localhost', 'username', 'password'); //Subject has connected!
I guess even that is sort of an observer even if it's not following that same pattern.
Posted: Tue Jun 06, 2006 6:06 pm
by daedalus__
I've never seen interface before but couldn't an observer be useful for error reporting or is all of the built-in stuff sufficient?
Posted: Tue Jun 06, 2006 6:25 pm
by Chris Corbyn
Daedalus- wrote:I've never seen interface before but couldn't an observer be useful for error reporting or is all of the built-in stuff sufficient?
This was mentioned in another thread today
I guess you could have silent errors (boolean responses) but allow an observer to display errors. I'm actually thinking now though that it's a total overkill doing that if the only purpose is to display errors. But you could however make the observer not display the error, rather write it to a log file or a database. If you needed something like that I guess an observer might work. To be honest I'm likely as much in the dark as you on this one
Let's see how it would look.
Code: Select all
class someClass
{
private $observers = array();
public function registerObserver($observer, $type)
{
if (!isset($this->observers[$type])) $this->observers[$type] = array();
$this->observers[$type][] = $observer;
}
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*/)
{
$this->notify(new errorMsg('Oops, something went wrong'));
return false;
}
else //just do something
}
}
class errorMsg
{
private $errorString;
public function __construct($error_string)
{
$this->errorString = $error_string;
}
public function getType()
{
return 'ERROR';
}
public function getErrorString()
{
return $this->errorString;
}
}
class errorHandler
{
public function notify($object)
{
if ($object instanceof errorMsg)
{
echo $object->getErrorString();
}
}
}
$someObject = new someClass;
$someObject->registerObserver(new errorHandler, errorMsg::getType());
$someObject->someMethodThatCanError();
Nah, seems a bit long winded.
Posted: Tue Jun 06, 2006 6:55 pm
by Chris Corbyn
OK I guess a big difference between the oberserver & observable vs. plugin & pluggable is that plugins can modify the behaviour of the pluggable, whereas observers don't actually do anything to the observable right? If observers can tinker with the workings of the observable, have they crossed some fine line into plugin territory and out of observer territory? Am I just rambling on now?
I think I'll leave this pattern behind for now and move on until I see a need for it in PHP

Posted: Tue Jun 06, 2006 7:32 pm
by Christopher
d11wtq wrote:OK I guess a big difference between the oberserver & observable vs. plugin & pluggable is that plugins can modify the behaviour of the pluggable, whereas observers don't actually do anything to the observable right? If observers can tinker with the workings of the observable, have they crossed some fine line into plugin territory and out of observer territory? Am I just rambling on now?

As ever with patterns the difference is often with intent. The intent of the Observer pattern is to notify some number of classes when an event occurs -- so it is a specific type of composite/component relationship. The Plugin is more akin to the Factory pattern in that that they allow multiple classes to be treated as one. With the Factory you are requesting objects, as opposed to the Plugin where you are talking to a interface. In either case you don't care what happens on the other side of the interface.
Posted: Tue Jun 06, 2006 8:12 pm
by sweatje
It might also help to know that the Observer pattern is also know as Publish/Subscribe. It is useful in cases where you have a source of data, and you want to be flexible at runtime with one or more different means of responding to the data. In my book, I show an example of using an Observer in a PHP4 error handler, with different observers logging errors to a file, or to syslog or sending an email. (as a point of interest, I still periodically get emails from people randomly testing the code without changing from my email address

)
Posted: Wed Jun 07, 2006 12:07 pm
by JPlush76
a good example of the observer pattern is in javascript
when a page loads you have an onload event that is fired in the browser. Sometimes you want to execute a function when the page loads... ok thats great but what if you want to execute 5 functions when the page loads? you could create a wrapper function to call that will then call each function but that is messy and not great to maintain. A better way is to use the observer pattern.
Here's a basic run through
while page is loading I register my 5 functions into an "observer" array
when the page is loaded the onload function loops through the array, calling each function to notify them the page has loaded.
Code: Select all
// SET UP OBSERVER PATTERN FOR LETTING JAVASCRIPT FUNCTIONS REGISTER THEMSELVES
onLoadListeners = new Array(); //container that will hold our observing functions
/**
* This function can be called globally in any page to add a function to be called for the onload event
*@param object A function name that should be called when the page is loaded IE: addOnLoad(myFunc);
*/
function addOnLoad(func) {
var listener = new Array();
listener['listener'] = func;
onLoadListeners.push(listener);
}
// loop through all our listeners and alert them the page has loaded
window.onload=function()
{
var len = onLoadListeners.length;
for(var i=0; i<len; i++) {
onLoadListeners[i].listener();
}
}
Posted: Wed Jun 07, 2006 12:10 pm
by JPlush76
a good PHP example would be message board postings...
You can use the observer pattern when someone posts a message
When a user posts a message you usually want to:
Send out email notification of a new post
Update post counts
Update other counters
Update your RSS feed
So if each of those puppies were objects waiting for a message you can use this pattern to loop through the observers (the list above) and then execute their method with a message of what just occured.
Its one of the best patterns around