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

PHP事件侦听器最佳实践实现,php,event-listener,Php,Event Listener,我正在尝试用PHP创建一个类似CMS的系统。使其尽可能模块化和可扩展 有人能给我提供一个最佳实践场景,用PHP创建一个事件监听器系统(例如Drupal系统的一个非常简化的版本),创建钩子并在一个简短的示例中实现它们也很好。如果您使用的是PHP5.3(因此可以访问丰富的闭包),我将使用中的事件/过滤器系统作为PHP设计的基础。好吧,从实现的角度来看,有三种不同的方法可以做到这一点(请注意,这些是OO设计模式,但如果您愿意,可以在功能上或程序上实现它们) 1。观察者模式 您可以实现。基本上,你会把每

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


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

如果您使用的是PHP5.3(因此可以访问丰富的闭包),我将使用中的事件/过滤器系统作为PHP设计的基础。

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

1。观察者模式

您可以实现。基本上,你会把每一件能引发事件的事情都作为一个主题。然后,您想要监听的类/代码绑定到它想要监听的特定对象。假设您有一个名为
Foo
的控制器。如果你想听它,你可以调用
$fooController->attach($observer)。然后,每当控制器想说什么,它就会将事件发送给所有的观察者

这非常适合通知系统(扩展类的功能)。它不太适合实时修改代码的行为

2。装饰图案 您还可以实现。基本上,您可以获取要修改的对象,并将其“包装”到一个新对象中,该对象可以执行您想要更改的操作。这非常适合修改和扩展行为(因为您可以有选择地重写包装类中的功能)

如果您已经定义了接口,并且希望对象符合这些接口,那么这将非常有效。如果您没有接口(或者没有正确地使用它们),装饰器模式可以为您做的大部分工作都将丢失

还要注意,这实际上不是一种处理事件的方式,而是一种修改对象行为的方式

3。中介模式

你也可以用一个。基本上,你会有一个全局中介来跟踪你的听众。如果要触发事件,则将事件发送给中介。然后,中介可以跟踪哪些侦听对象希望接收该事件,并正确地传递消息

这样做的好处在于它是中心的。这意味着多个发送者可以发送相同的事件,而对于侦听者来说,发送事件的人没有区别


我在几个项目中就是这样做的

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

 $obj = _new('SomeClass', $x, $y); // instead of $obj = new SomeClass($x, $y);
与原始
new
相比,这有许多优点,从事件处理的角度来看,
\u new()
维护所有已创建对象的列表非常重要

还有一个全局函数
send($message,$params)
迭代此列表,如果对象公开了“on_$message”方法,则调用此方法,并传递参数:

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), $_);
}

因此,例如,
send('load')
将为已定义的每个对象调用
on\u load
方法。

这可能会引起您的兴趣:-1因为这并不能真正回答如何创建事件侦听器库的问题。这应该是一个评论。+1因为锂离子电池是如何进行活动/聆听的一个很好的例子。第一次思考有点困难,但它非常强大:,。将锂元素的灵感与PHP5.4中的流过滤器、令牌反射、装饰器、切入点和闭包结合在一起,形成了真正的AOP框架:,需要探索真正的实现,WordPress使用add_操作和其他一些东西来实现观察者模式。这并不漂亮,但很有效。@Casey:这是中介模式,不是观察者模式。任何时候你不想直接听的东西,那就是中介模式。但这是一个OO设计模式的过程实现的例子。。。这是一个非常有用的评论…@ircmaxwell-谢谢你的澄清,非常感谢。谢谢你的透彻解释,我想知道你是否能为我提供一个观察者模式的简单具体例子谢谢你的回答和你的链接文章哇…非常聪明的方法!简单有效。有些用户可能更喜欢调用\u user\u func\u数组,将$args分解为单独传递的变量,而不是将数组作为唯一的参数。谢谢Erwinus,我知道你要求关闭,但为什么?您还可以引用一个非匿名的类方法。也许你也想调用一个普通的函数/方法。@user3292653:如果你不同意,可以随意更改,源代码是免费的;-)不要使用静电传感器。这段代码将来很难模拟或测试。即使是延长也会受到限制。(这也打破了坚实的原则)@JohnTribe:以前你更改了代码(根本没有任何意义),现在你又大喊大叫了。你不同意没关系,提示:不要使用它。
/*
 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;
    }
}