Louis Mullie [2005-01-01 16:47 UTC] Nice. I've been trying to implement this unsuccessfully for a long time. This could also be used to achieve true MVC frameworks where the View "subscribes" to the Model and is notified of it's changes, allowing a true reflection of the Model's state. One little mistake I think, $notification = new Mamasam_Core_Notification($object, $nName, $info); instantiates a non-existent class (you probably renamed it Notification...)
Regards,
Louis Mullie
Bertrand Mansion [2005-01-01 17:01 UTC] >$notification = new Mamasam_Core_Notification($object, $nName, $info);
That's correct, thanks for noticing, I have now fixed it :)
Markus Wolff [2005-01-02 23:57 UTC] Quite nice. I got something similar here:
http://opensource.21st.de/tiki-index.php?page=EventController
...it's PHP5 only, though.
Did want to make this into a PEAR proposal some time ago, but somehow never got to that.
I'd like something like this very much in PEAR, to have a standard way of dealing with events that all packages can follow. It really sucks that everyone is reinventing the wheel ATM.
Lukas Smith [2005-01-03 00:18 UTC] I have only briefly looked at your code, but we have added observer support to LiveUser recently:
http://cvs.php.net/co.php/pear/LiveUser/LiveUser.php
see lines 1454-1513
then again it didnt take that many lines for our particular case .. so we need to watch out that we dont get into eventually having to include several pattern packages to be political correct :-)
maybe an interface definition with a reference implemention of an observer pattern is a viable alternative
Alan Knowles [2005-01-03 02:34 UTC] My original thoughts where that emulating gobjects signal model may be an idea.
eg. signal::connect($obj,'signame',$callback,$args...);
signal::register('class','signame');
signal::emit($obj, 'eventname',$args);
But the more I look at it, something that follows W3C events API may be more familar.
Event::register('classname','event');
Event::addListener($obj, 'event', $callback, $args);
Event::removeListener($obj, 'event',$callback);
Event::emit($obj|classname, 'event',$args);
you could then wrap these in your own class:
function addEventLister('event',$callback,$args) {
Event::addListener($this, 'event', $callback, $args);
}
Without resorting to a yourclass extends Event, however it's a little complex implement object instance listeners using a vistor pattern (as it's difficult to get object instance ID's from the registered instance AFAIR)
Ideally all this would be done by PHP internals (using an Event Interface) - in a similar way to Iterators..
Greg Beaver [2005-01-03 06:30 UTC] I agree with the idea of defining interfaces first, and having a sample implementation or default implementation of this interface.
This way, people can count on the same system for event notification, without requiring more code if a package only needs to implement a portion of this.
Alan has brought up the idea of getting this pattern into something like SPL before on internals, maybe it is a better time to bring it up again there too, this would greatly simplify Bertrand's excellent efforts.
I have also attempted to implement something that would provide more than just notification, but two-way messaging. In my experiments, there was no reason to require the use of an object to encase the message, as the data format was most easily defined/constrained by the message type/intended recipient type. After all, nobody will handle messages that are not intended for them, so who cares what the format is? This provides a tremendous performance gain at the same time that flexibility increases, and results in significantly smaller code. I can unearth my old work if you are interested.
Bertrand Mansion [2005-01-04 12:17 UTC] Markus:
I have read your slides (me being flussig in German as you know ;)) and obviously we are talking about the same thing. The main difference is the implementation. Your design is more "complex", meaning you have more classes, interfaces and instructions of use. The notification center I propose registers PHP callbacks instead of objects because they are native for PHP and do the job perfectly. IMO, there is no need to add a wrapper around them. Their syntax allows for both methods and functions call, which is a nice feature too as everything is still not object in PHP.
More importantly, PHP callbacks are a native structure, both well-known and ready-to-use, which means users get it fast.
The other important difference is that ANY objects can post a notification. It doesn't have to extend another class for that. Which means the system is totally plug and play.
Lukas:
I have looked at the code you pointed out in LiveUser. This is of course a solution but it is IMO not as handy as having a central notification system. It forces developers to add and implement these methods (with a risk of having different implementations, ie you use an Error_Stack while others might trigger a warning or simply ignore the case where an event is not registered). It also forces them to follow a way that might not suit their needs.
I think these methods bloat to your objects. These 40 lines of codes (repeated in every objects using observers) seems too much in regard of the following:
<code>
// Registering for a notification
if (class_exists('NotificationCenter')) {
$nc = NotificationCenter::defaultCenter();
$nc->addObserver(array($this, 'userLogged'), 'UserDidLoginNotification');
}
// Posting a notification
if (class_exists('NotificationCenter')) {
$nc = NotificationCenter::defaultCenter();
$nc->postNotififcation($this, 'UserDidLoginNotification');
}
</code>
The NotificationCenter also allow some filters based on the class posting the notification for example, or the name of the notification.
You can also have objects (for debug purpose for instance) that want to listen to all notifications.
A notification can also be posted before the observer has registered, it will still be notified if the user wants it to. You don't have to worry about the order you instantiated your objects.
There could be more than one notification center (although this is not yet implemented).
To finish with, there are cases when you want to give another object as parameter than the one sending the notification, this is possible too. Those are features not supported in your solution.
Alan:
The W3C events API you suggest looks very similar to the one I have. But I feel strongly against forcing classes to extend an Event object. That's the idea behind a notification center. In the end, I agree that it would be nice to have something like this in PHP internals but it is not done yet. In a way, it's like DB and PDO, PEAR_Error and Exceptions, etc. It is PHP4 (although a PHP5 version using filter iterators could be nice...).
Greg:
The notification center is a plug-and-play solution, you don't have to modify your APIs and you are free to use it or not. Having a notification center does not mean you can't have an interface to make your objects "observable" in any other way but it is a lighter, centralized, solution that is ready to use.
I am not sure I understand your 2-way messaging thing. I wrap the notifications in a Notification object in order to provide a common API to users so that they know what to expect from objects they might not know well. The Notification class can also be easily extended and the subclass can be used by $nc->post($notificationSubclass);
In the package documentation, users will only have to tell which kind of notifications (their name) are posted by the object and when.
Lukas Smith [2005-01-04 13:18 UTC] Since we dont have multiple inheritance having to inherit from some object is a no go like Bertrand already mentioned in his reply. You can however implement multiple interfaces so the interface route seems to make the most sense.
So Bertrand the idea behind the Notification center is similar in a way to ErrorStack. It means that every class that wants to use the Notification center loads the code and then allows observers to register for that class (or rather instances).
This would obviously prevent redundant code. It would provide more I/O overhead which would however become less relevant expensive per package the more packages use the notification center. So far we have only done this for the PEAR base class (something we have gotten a bad name for, however mainly due to design mistakes we mostly fixed by now). Its a fundamental descision: Do we want to prevent code redundancy even if that means that packages need to then require several (error handling, notification center .. etc) infrastructure packages?
That is why I proposed the alternative of simply having a common interface with a reference implementation (or maybe several for different specific needs) that people essentially cut and paste. I am not so worried about lines of code here. I am more worried about number of required files.
Michael Wallner [2005-01-12 12:04 UTC] I gonna need this -- now. ;)
You may want to use strcasecmp() on class names retrieved with get_class() instead of loads of strtolower().
Bertrand Mansion [2005-01-12 12:42 UTC] Michael,
I plan on making a PHP5 version only, that will maybe use a limit iterator and call the package Event/Dispatcher.php
with classes:
- Event_Dispatcher
- Event_Notification
Would that also fit your needs or is a PHP4 version also required ?
Michael Wallner [2005-01-12 13:18 UTC] Oh, that would really be a pity...
I know that working with objects is a lot less painfull in PHP5, but I'm still developing applications in PHP4 and probably will do so until php-internals have vastly decided where PHP5's going to move, which I estimate at/after v5.1
I don't know how others feel, so I may belong to the minority, though... :)
Lukas Smith [2005-01-12 13:31 UTC] Well I dont know where you want to add that iterator, but maybe this can be solved via a conditional include? For example in MDB2 I have an Iterator interface for PHP5 that people can optionally use.
Bertrand Mansion [2005-01-12 13:46 UTC] OK, so I will just clean up the code, try to refactor some stuff, maybe change methods names and if Event_Dispatcher as a name is approved, I will call for vote. So this will stay PHP4, while a possible Event_Dispatcher2 will be PHP5 later on, only if it is faster.
Helgi Þormar Þorbjörnsson [2005-01-12 14:09 UTC] I agree with Mike here, I'll be working with PHP4 also until 5.1 at least, at least at work :/
And this seems to be something I could make use of :)
Arnaud Limbourg [2005-01-12 21:02 UTC] looks very interesting
Arnaud Limbourg [2005-01-13 14:00 UTC] About the category.
Some packages are in categories which do no really match their goal (phpunit is in the PHP category which serves almost like a misc. category)
Would it make sense to introduce a Foundation category ? The reasoning is that these would classes which can/are recommended to be used by other packages. The notification center would clearly fit into this.
Ideas/Thoughts/Opinions ?
Bertrand Mansion [2005-01-13 15:03 UTC] That would be a good category IMO.
Things like ErrorStack could fit in there too.
For the package, I am pretty much settled on Event_Dispatcher + Event_Notification.
I am uploading the updated/improved sources today.
|