to('hook1', 'hook2', ...); // register func(s) to hook(s)
// Plug::applyToAll('func1', 'func2', ...); // register func(s) to all hooks
// Plug::send($arg1, $arg2, ...)->to('hook1', 'hook2', ...); // call hook(s)
//
//-------------------------------------------------
class Plug
{
//-------------------------------------------------
// Is this hook being registered or called?
//-------------------------------------------------
protected $register = FALSE;
//-------------------------------------------------
// An array of hook ids that have been used.
//-------------------------------------------------
static protected $ids = array();
//-------------------------------------------------
// An array of the function names / class & function
// names of the hooks that are being applied.
//-------------------------------------------------
static protected $hooks = array();
//-------------------------------------------------
// An array of hooks that are applied to all hooks when
// executed.
//-------------------------------------------------
static protected $globals = array();
//-------------------------------------------------
// Arguments passed to Plug::send() to pass to the hooks
// being called. After Plug::send()->to() is called,
// this array is reset.
//-------------------------------------------------
static protected $args = array();
//-------------------------------------------------
// Function names passed to Plug::register() to pass
// to the hooks being registered. After Plug::register()->to()
// is called, this array is reset.
//-------------------------------------------------
static protected $funcs = array();
//-------------------------------------------------
// Constructor, this is only called if we are calling
// or registering a hook.
//-------------------------------------------------
public function __construct($register = FALSE)
{
$this->register = (bool)$register;
}
//-------------------------------------------------
// Register a global hook, this is a function that is
// applied to all hooks, public method.
//-------------------------------------------------
static public function applyToAll()
{
$funcs = func_get_args();
foreach($funcs as $str)
{
//-------------------------------------------------
// This global doesn't exist yet so let's register it.
//-------------------------------------------------
if(!in_array($str, self::$globals))
{
self::$globals[] = $str;
}
//-------------------------------------------------
// This is a new global hook so we need to manually
// go through all of the hook ids and add this function.
// This would seem counterintuitive but the whole point
// is to maintain order.
//-------------------------------------------------
foreach(self::$ids as $id)
{
self::registerHook($id, $str);
}
}
}
//-------------------------------------------------
// Register a hook, this applies a function to a hook
// id for both single and global hooks, private method.
//-------------------------------------------------
static protected function registerHook($id, $str)
{
//-------------------------------------------------
// If this hook id has not been used yet, then lets
// register it and add all of our global hooks, in the
// order that they were added.
//-------------------------------------------------
if(!in_array($id, self::$ids))
{
self::$ids[] = $id;
foreach(self::$globals as $func)
{
self::registerHook($id, $func);
}
}
//-------------------------------------------------
// Now, let's go and see if we need to add a function/
// class method as the hook.
//-------------------------------------------------
if($str != '')
{
if(strpos($str, '::') !== FALSE)
{
list($class, $method) = explode('::', $str);
if(class_exists($class))
{
self::$hooks[$id][] = array($class, $method);
}
}
else
{
if(function_exists($str))
{
self::$hooks[$id][] = array($str);
}
}
}
}
//-------------------------------------------------
// Set the arguments to send to a hook.
//-------------------------------------------------
static public function send()
{
self::$args = func_get_args();
return new self(FALSE);
}
//-------------------------------------------------
// Set the function to register a hook(s) to.
//-------------------------------------------------
static public function apply()
{
self::$funcs = func_get_args();
return new self(TRUE);
}
//-------------------------------------------------
// Call/register a hook / multiple hooks at the same time.
//-------------------------------------------------
public function to()
{
$args = func_get_args();
//-------------------------------------------------
// Register the hooks.
//-------------------------------------------------
if($this->register)
{
foreach($args as $id)
{
foreach(self::$funcs as $func)
{
self::registerHook($id, $func);
}
}
self::$funcs = array();
}
//-------------------------------------------------
// Call the hooks.
//-------------------------------------------------
else
{
foreach($args as $id)
{
self::callHooks($id, self::$args, FALSE);
}
self::$args = array();
}
}
//-------------------------------------------------
// Call all of the hooks of a specific id. $keep_going
// is to stop possible infinite loops.
//-------------------------------------------------
static protected function callHooks($id, $args, $keep_going = FALSE)
{
$call = FALSE;
if(isset(self::$hooks[$id]) && !empty(self::$hooks[$id]))
{
//-------------------------------------------------
// Go through this functions hooks and execute them.
//-------------------------------------------------
foreach(self::$hooks[$id] as $hook)
{
if(isset($hook[1]))
{
$obj = new $hook[0];
if(method_exists($obj, $hook[1]))
{
$call = array(&$obj, $hook[1]);
}
}
else
{
$call = $hook[0];
}
//-------------------------------------------------
// Call the hook.
//-------------------------------------------------
if($call)
{
call_user_func_array($call, $args);
}
}
}
else
{
//-------------------------------------------------
// If there are global hooks but no single custom hooks
// have been applied to this hook yet, then add all of the
// global hooks and re-call this function.
//-------------------------------------------------
if(!$keep_going && !empty(self::$globals))
{
self::registerHook($id, '');
self::callHooks($id, $args, TRUE);
}
}
}
}
//-------------------------------------------------
// Whatever, a random useless class.
//-------------------------------------------------
class Whatever
{
//-------------------------------------------------
// A random function that calls some hooks. This function
// doesn't need to be in a class but whatever.
//-------------------------------------------------
public function moo()
{
Plug::send()->to('before_moo');
echo 'hi';
Plug::send('after')->to('after_moo');
}
//-------------------------------------------------
// This is a hooked function.
//-------------------------------------------------
public function hooked($arg)
{
echo '
This gets called '. $arg .'.';
}
}
//-------------------------------------------------
// This is a hooked function.
//-------------------------------------------------
function test()
{
echo 'This gets called before.
';
}
//-------------------------------------------------
// Register the hooks.
//-------------------------------------------------
Plug::apply('test')->to('before_moo');
Plug::apply('Whatever::hooked')->to('after_moo');
Plug::applyToAll('some_func');
//-------------------------------------------------
// Call our function which executes the hooks.
//-------------------------------------------------
$whatever = new Whatever;
$whatever->moo();
?>