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:

  1. 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.
  2. 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;
	}
	
}