How to add events to a PHP project
Here is a short class that will let you add events to a PHP project.
The class EventManager defines a singleton, which you access with the EventManager::getInstance() expression.
Here is the logic:
- bind a handler to an event: EventManager::getInstance()->bind( ‘event’, ‘handler’ )
An event can be a string or a PHP regular expression. A handler must be a PHP callable expression. - trigger an event: EventManager::getInstance()->trigger( ‘event’ )
A triggered event should be a string. That string is going to be matched against all the bound events. Whenever a match is found, all the handlers bound to the matching events will be called. All the arguments passed to trigger will be passed along to the handlers. If a handler returns a false value, all other handlers won’t be called.
class EventManager {
/**
* Singleton setup
*/
static protected $_instance = null;
protected function __construct() {}
protected function __clone() {}
static public function getInstance() {
if (is_null( self::$_instance )) {
$class = __CLASS__;
self::$_instance = new $class();
}
return self::$_instance;
}
/**
* Stores bindings between events and their handlers
*
* @var array
*/
protected $_bindings = array();
/**
* Returns the id of the given $handler
*
* @param $handler a callable expression
* @return string
*/
protected function getId( $handler ) {
if (! is_callable( $handler )) {
throw new Exception('Expected a callable expression');
}
if (is_string( $handler )) {
$id = "function: $handler";
} else {
$container = $hadler[0];
$method = $handler[1];
if (is_string( $container )) {
$class = $container;
$id = "class: $class, method: $method";
} else {
$class = get_class( $container );
$object = spl_object_hash( $container );
$id = "class: $class, object: $object, method: $method";
}
}
return $id;
}
/**
* Returns TRUE if the given $expression is a regular expression in PHP
* TODO improve EventManager::isRegExp by allowing matching delimiters (), [], {}, <>
*
* @param $regex
* @return boolean
*/
protected function isRegExp( $expression ) {
if (is_string( $expression ) && preg_match( '/([^\w \\])[^\1\\\r\n]*(?:\\.[^\1\\\r\n]*)*\1/', $expression )) {
return true;
}
return false;
}
/**
* Binds a $handler to an $event
*
* @param string $event
* @param callable $handler
* @return EventManager
*/
public function bind( $event, $handler ) {
$id = $this->getId( $handler );
$this->_bindings[ $event ][ $id ] = $handler;
return $this;
}
/**
* Unbinds a $handler from an $event
*
* @param string $event
* @param callable $handler
* @return EventManager
*/
public function unbind( $event, $handler = null ) {
if (is_null( $handler )) {
unset( $this->_bindings[ $event ] );
} else {
$id = $this->getId( $handler );
unset( $this->_bindings[ $event ][ $id ] );
}
return $this;
}
/**
* Dispatches a $triggered event to all its matching handlers
*
* @param string $triggered
* @return EventManager
*/
public function trigger( $triggered ) {
$result = true;
$args = func_get_args();
foreach ($this->_bindings as $event => $handlers) {
if ($this->isRegExp( $event )) {
if (! preg_match( $event, $triggered )) {
continue;
}
} else {
if ($event != $triggered) {
continue;
}
}
if (is_array( $handlers )) {
foreach ($handlers as $handler) {
if (is_callable( $handler )) {
$result = call_user_func_array( $handler, $args );
if (false === $result) {
break;
}
}
}
}
if (false === $result) {
break;
}
}
return $this;
}
}