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(); ?>