PHP has the drawback of not supporting events. Fortunately, a basic structure can be built to support events in PHP 5. This article tackles that problem with some proof of concept code.
To enable a class with events, there are a few prerequisites, given our existing classes. First, it needs to contain a list of available events. Second, it needs to be able to trigger, or raise, its events through some helper method. Third, it needs to be able to register event handlers. Note that any given event can have more than one event handler.
The code for this class, which we are calling MyEventClass, is actually pretty simple. In the code below, you will notice that the class is wired up for two events, OnLoad and OnUnload. You will also notice that we pass an EventHandlerCollection into the constructor. To support the OnLoad event, which fires at the end of the constructor, we would have to already have a handler in place to make use of it – which means, in general, classes implementing this pattern will need to provide a $handlers parameter in the constructor.
class MyEventClass { private $events; private $eventHandlers;
public function __construct(EventHandlerCollection $handlers = null) { $this->events = new EventCollection();
if ($handlers) $this->eventHandlers = $handlers; else $this->eventHandlers = new EventHandlerCollection ();
public function __destruct() { $this->TriggerEvent('OnUnload', array('arg2'=>2)); }
public function RegisterEventHandler($handler) { if ($this->events->Contains($handler->GetEventName())) $this->eventHandlers->Add($handler); } private function InitEvents() { $this->events->Add(new Event('OnLoad')); $this->events->Add(new Event('OnUnload')); } private function TriggerEvent($eventName, $args) { $this->eventHandlers->RaiseEvent($eventName, $this, $args); } }
To quickly review the class methods, from the bottom up, there is TriggerEvent(), which accepts an event name and any relevant arguments. It directly calls EventHandlerCollection::RaiseEvent, which passes the event along to the appropriate handler or handlers, if one does in fact exist. Since the RaiseEvent() method of EventHandlerCollection does not have an exit condition when it finds a handler matching the raised event, we can have as many handlers for an event as we want.
InitEvents() is a crude way to register available events with the class. We have to populate the EventCollection somehow, and this seemed to me the best way to do it. RegisterEventHandler() is simply a wrapper for EventHandlerCollection::Add(), allowing us to attach handlers to an object after it has been instantiated. I would suggest passing all handlers in the constructor for clarity's sake, but the RegisterEventHandler() method is available nonetheless.
Notice in __construct() and __destruct(), TriggerEvent() is called. The result of calling TriggerEvent(), through a few levels of indirection, calls the code you passed in when you created your EventHandlers. That brings me to the final bit of code for this article – using MyEventClass.