PHP事件监听器最佳实践实现

H.J*_*sef 49 php event-listener

我正在尝试用PHP创建类似CMS的系统.使其尽可能模块化和可扩展.

有人能为我提供在PHP中创建事件监听器系统的最佳实践场景(例如Drupal系统的一个非常简化的版本),创建钩子并在一个简短的例子中实现它们也会很好.

irc*_*ell 132

那么,从实现的角度来看,实际上有三种不同的方法(请注意,这些是OO设计模式,但如果您愿意,可以在功能上或程序上实现它们).

1.观察者模式

您可以实现观察者模式.基本上,你可以将每件可以引发事件的东西都当作主题.然后,您想要监听的类/代码将特定地绑定到它想要听的内容.所以假设你有一个名为的控制器Foo.如果你想听它,你可以打电话$fooController->attach($observer);.然后,每当控制器想要说些什么时,它就会将事件发送给所有观察者.

这非常适合于通知系统(扩展正在进行的类).它不太适合实时修改代码行为.

2.装饰器模式 您还可以实现装饰器模式.基本上,您获取要修改的对象,并将其"包装"在一个新对象中,该对象执行您想要更改的内容.这非常适合修改和扩展行为(因为您可以有选择地覆盖包装类中的功能).

如果您已定义接口并期望对象符合它们,则此方法非常有效.如果你没有接口(或者没有正确使用它们),那么装饰器模式可以为你做的大部分都将丢失.

还要注意,这实际上不是一种做事件的方式,它是一种修改对象行为的方法.

3.中介模式

您也可以使用Mediator.基本上,你有一个全局调解员可以跟踪你的听众.如果要触发事件,请将事件发送给调解器.然后,介体可以跟踪哪些侦听对象想要接收该事件,并正确传递消息.

这具有中心的优势.这意味着多个发件人可以发送相同的事件,并且对于听众而言,发送它的人没有什么区别......

我在博客文章中扩展了这个主题.

  • @Casey:这是Mediator模式,而不是Observer模式.任何时候你没有附加到你想要直接听的东西,它就是中介模式.但它是OO设计模式的程序实现的一个例子......所以这是一个非常有用的评论...... (5认同)
  • 对于要探索的实际实现,WordPress使用add_action和其他一些东西来实现Observer模式.它不漂亮,但它往往起作用. (2认同)

Cod*_*eat 33

/*
 Example 1: 
 event::bind('blog.post.create', function($args = array())
 {
    mail('myself@me.com', 'Blog Post Published', $args['name'] . ' has been published');
});

 Example 2: 
 event::trigger('blog.post.create', $postInfo);
*/

class event
{
    public static $events = array();

    public static function trigger($event, $args = array())
    {
        if(isset(self::$events[$event]))
        {
            foreach(self::$events[$event] as $func)
            {
                call_user_func($func, $args);
            }
        }

    }

    public static function bind($event, Closure $func)
    {
        self::$events[$event][] = $func;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 简单有效.有些用户可能更喜欢使用call_user_func_array将$ args分解为单独传递的变量,而不是将数组作为唯一参数.谢谢Erwinus. (2认同)
  • 我知道你要求Closure的对象,但为什么呢?您还可以引用非匿名的类方法.也许你想调用一个普通的函数/方法. (2认同)

use*_*291 13

这就是我在几个项目中的表现

使用构造函数而不是new运算符创建所有对象.

 $obj = _new('SomeClass', $x, $y); // instead of $obj = new SomeClass($x, $y);
Run Code Online (Sandbox Code Playgroud)

与raw相比,这有许多优点new,从事件处理的角度来看,_new()维护所有已创建对象的列表非常重要.

还有一个send($message, $params)遍历此列表的全局函数,如果对象公开方法"on_ $ message",则调用此方法,传递params:

function send() {
    $_ = func_get_args();
    $m = "on_" . array_shift($_);
    foreach($_all_objects as $obj)
        if(method_exists($obj, $m))
            call_user_func_array(array($obj, $m), $_);
}
Run Code Online (Sandbox Code Playgroud)

因此,例如,send('load')将为on_load每个定义它的对象调用方法.