The EventHandler and EventHandlerCollection Classes - PHP
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 create an event handler, we need to know the event to which it was attached and we need to know what to do when the handler finds out about the event being raised. Since we cannot create function references, and lack of native support for events eliminates the usefulness of anonymous functions, we will use an approach similar to C# delegates, but with less fuss. We will create an EventHandler object by passing it an Event object and the name of the callback function, which will later be called in an eval() statement (ugly, but it will do).
class EventHandler { private $event; private $callback;
public function GetEventName() { return $this->event->GetName(); }
public function __construct($event, $callback) { $this->event = $event; $this->callback = $this->PrepareCallback($callback); }
public function Raise($sender, $args) { if ($this->callback) eval($this->callback); }
private function PrepareCallback($callback) { if ($pos = strpos($callback, '(')) $callback = substr($callback, 0, $pos);
$callback .= '($sender, $args);';
return $callback; } }
This class actually has some substance to it. The Raise() method actually runs the callback, and the PrepareCallback() method makes sure the callback has the proper signature for a delegate, that is, (Object $sender, EventArgs $e), for those of you who are familiar with C#. Since I didn’t care to make an EventArgs class, $args will just be an array. This provides the handler functions with context that they would otherwise lack. They know the calling object, $sender, and they can be given parameters with $args.
The EventHandlerCollection also provides a test for membership with the Contains() method, basically what we saw with the EventCollection, and it provides a RaiseEvent() method that picks through its list of handlers and calls Raise() on the right one. This keeps event triggering simple later on when we look at the event enabled class. Here is the EventHandlerCollection class:
class EventHandlerCollection { private $handlers;
public function __construct() { $this->handlers = new ArrayObject(); }
public function Add($handler) { $this->handlers->Append($handler); }
public function RaiseEvent($event, $sender, $args) { foreach ($this->handlers as $handler) { if ($handler->GetEventName() == $event) $handler->Raise($sender, $args); } } }
We now have our four “framework” classes. It is time to move on to a class that can actually register event handlers and raise events.