Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP: How to realize event handler?

I want to add custom event handler to object's method.

I've got a class with method.

class Post {

    public function Add($title) {

        // beforeAdd event should be called here

        echo 'Post "' . $title . '" added.';
        return;
    }
}

I want to add an event to method Add and pass method's argument(s) to the event handler.

function AddEventHandler($event, $handler){
    // What should this function do?
}

$handler = function($title){
    return strtoupper($title);
}

AddEventHandler('beforeAdd', $handler);

Is it possible to do something like this? Hope my question is clear.

like image 215
foreline Avatar asked Oct 09 '10 16:10

foreline


4 Answers

Should be pretty easy using the functions defined here http://www.php.net/manual/en/book.funchand.php

In particular you should keep an handler array (or array of arrays if you want multiple handlers for the same event) and then just do something like

function AddEventHandler($event, $handler){
    $handlerArray[$event] = $handler;
}

or

function AddEventHandler($event, $handler){
    $handlerArray[$event][] = $handler;
}

in case of multiple handlers.

Invoking the handlers then would be just matter of calling "call_user_func" (eventually in a cycle if multiple handlers are needed)

like image 169
Bitgamma Avatar answered Oct 12 '22 23:10

Bitgamma


Well, if you are using < php 5.3 then you cannot create a closure in such a way, but you can come close with create_function(); This would be

$handler = create_function('$title', 'return strtoupper($title);');

Then you store $handler in the class and you can call it as you desire.

like image 35
Explosion Pills Avatar answered Oct 12 '22 23:10

Explosion Pills


Methods

You have multiple methods how to do it described by ircmaxell here.

And here is ToroHook used in ToroPHP (Routing lib).

Hook

class ToroHook {
    private static $instance;
    private $hooks = array();

    private function __construct() {}
    private function __clone() {}

    public static function add($hook_name, $fn){
        $instance = self::get_instance();
        $instance->hooks[$hook_name][] = $fn;
    }

    public static function fire($hook_name, $params = null){
        $instance = self::get_instance();
        if (isset($instance->hooks[$hook_name])) {
            foreach ($instance->hooks[$hook_name] as $fn) {
                call_user_func_array($fn, array(&$params));
            }
        }
    }
    public static function remove($hook_name){
        $instance = self::get_instance();
        unset($instance->hooks[$hook_name]);
        var_dump($instance->hooks);
    }
    public static function get_instance(){
        if (empty(self::$instance)) {
            self::$instance = new Hook();
        }
        return self::$instance;
    }
}

Using hook

It is simple call it like this:

ToroHook::add('404', function($errorpage){
    render("page/not_found", array("errorpage" => $errorpage));
});
like image 22
VeeeneX Avatar answered Oct 12 '22 23:10

VeeeneX


Take look on my sphido/events library:

  • it's easy to use (few lines of code)
  • based on PHP Function handling
  • allow prioritising listeners
  • add/remove listeners
  • filter values by functions
  • stop propagation in function chain
  • add default handler

Event handler example

on('event', function () {
  echo "wow it's works yeah!";
});

fire('event'); // print wow it's works yeah!

Filter function example

add_filter('price', function($price) {
  return (int)$price . ' USD';
});

echo filter('price', 100); // print 100 USD
like image 39
OzzyCzech Avatar answered Oct 13 '22 01:10

OzzyCzech