One of the nice features of WordPress is the plugin system, where ‘hooks’ allow custom functionality to be added without monkeying around with the core functionality.
I haven’t played around with this myself yet, but from what I could gather from the documentation, it does this using functions which are all defined in the global scope.
I was wondering today whether similar functionality could be achieved using a more object-oriented approach.
I wanted to be able to extend core functionality of one object by registering ‘hook’ methods on other objects at specific execution points. So I threw together the following code as a demo:
/**
* Binding class - represents a single event binding
*/
class Binding {
var $oObj;
var $sMethod;
/**
* Constructor
* @param object &$oObj the object on which we wish to call a method, passed by referenct
* @param string $sMethod the method to call
*/
function __construct(&$oObj, $sMethod) {
$this->oObj = $oObj;
$this->sMethod = $sMethod;
}
/**
* Trigger the event
* @param $aArgs an array of arguments for the bound function
*/
function trigger($aArgs = array()) {
call_user_func_array(array($this->oObj, $this->sMethod), $aArgs);
}
}
/**
* Singleton class to hold all event bindings
*/
class Hook {
/**
* Stores the static instance of this object - singleton design pattern
* @param object
*/
private static $instance;
/**
* Array of hooks
*/
private $aHooks = array();
/**
* Constructor
*/
private function __construct() {
}
/**
* get instance of this object
*/
public static function getInstance() {
if (!self::$instance)
{
self::$instance = new Hook();
}
return self::$instance;
}
/**
* Bind functionality
* @param string $sEvent the name of the event to bind
* @param object &$oObj the object whose method we wish to call
* @param string $sMethod the method to call
*/
function bind($sEvent, &$oObj, $sMethod) {
$this->aHooks[$sEvent][] = new Binding($oObj, $sMethod);
}
/**
* Trigger a bound event
* @param string $sEvent the event to trigger
* @param array $aArgs an array of arguments to pass to the bound function
*/
function trigger($sEvent, $aArgs = array()) {
if(array_key_exists($sEvent, $this->aHooks)) {
foreach($this->aHooks[$sEvent] as $key => $Binding) {
$Binding->trigger($aArgs);
}
}
}
}
class Extend {
function __construct() {
$Hook = Hook::getInstance();
$Hook->bind('pre', $this, 'beforeDoSomething');
$Hook->bind('post',$this, 'afterDoSomething');
}
function beforeDoSomething($arg) {
echo '<li>This before... the calling function wanted to say"' . $arg . '"';
}
function afterDoSomething($arg) {
echo '<li>The calling function said "' . $arg . '"';
}
}
class Extend2 {
function __construct() {
$Hook = Hook::getInstance();
$Hook->bind('post', $this, 'beforeDoSomething');
}
function beforeDoSomething() {
echo '<li>This is done in a second extended object';
}
}
/**
* Class providing base functionality
*/
class Base {
function __construct() {
}
function doSomething() {
$Hook = Hook::getInstance();
$Hook->trigger('pre', array("I'm about to start doing something..."));
echo '<li>doing the core functionality...';
$Hook->trigger('post', array("Ok I'm all done now!"));
}
}
$Base = new Base();
$Extend = new Extend();
$Extend2 = new Extend2();
$Base->doSomething();
Hopefully someone will find it useful
Thank you. It is surprisingly hard to find good code that shows how hooking can be done in PHP5. Have you worked any more on this? If you have any other deep insights into how to build a nice hook/plug-in system in PHP5 I’d be really interested in a mail ;o)
This is amazing, thank you fro a great sample and idea