开放的编程资料库

当前位置:我爱分享网 > PHP教程 > 正文

一个简单的 PHP 发布-订阅系统

最近我经常使用Dojo,对其优雅的发布-订阅系统印象深刻。基本上,任何对象都可以发布一个事件,而任何其他对象都可以订阅它。这创建了一个非常灵活的完全选择加入的通知架构。

该系统具有面向方面编程(AOP)的元素,以及观察者模式。然而,它的强大之处在于,一个单独的对象不需要实现任何特定的接口就可以充当Subject或Observer;该系统在全球范围内可用。

作为一个看到好点子就认出来的开发者,我当然决定把这个点子移植到PHP上。你可以在github上看到结果。

用法非常简单:一个对象发布一个事件,该事件触发所有订阅者。

可能最具说明性的解决方案是可选的日志记录。例如,您在应用程序引导程序中创建了一个记录器实例;然后您可以将其订阅到所有“日志”事件:

$log = new Zend_Log(new Zend_Log_Writer_Stream('/tmp/application.log'));
Phly_PubSub::subscribe('log', $log, 'info');

然后,在您的代码中,每当您可能想要记录一些信息时,只需发布​​到“日志”主题即可:

Phly_PubSub::publish('log', 'Log message...');

在生产中,您可以简单地注释掉日志定义和订阅,从而在整个应用程序中禁用日志记录。在没有订阅者的情况下发布到主题的事件只会提前返回——这意味着不会对使用该系统的代码产生任何影响。然后,您可以在需要调试或确定触发的事件时随意启用记录器。

作为另一个示例,考虑一个具有save方法的模型。您可能想要记录发送给它的数据以及返回的ID。此外,您可能希望在项目保存到您的持久性存储后更新您的搜索索引和缓存。

您模型的save方法可能如下所示:

class Foo
{
    public function save(array $data)
    {
        Phly_PubSub::publish('Foo::save::start', $data, $this);

        // ...

        Phly_PubSub::publish('Foo::save::end', $id, $this);
        return $id;
    }
}

在其他地方,您可能已经定义了记录器、索引器和缓存。在定义这些内容的地方,您会告诉他们您要订阅的主题。

Phly_PubSub::subscribe('Foo::save::start', $logger, 'logSaveData');
Phly_PubSub::subscribe('Foo::save::end', $logger, 'logSaveId');
Phly_PubSub::subscribe('Foo::save::end', $cache, 'updateFooItem');
Phly_PubSub::subscribe('Foo::save::end', $index, 'updateFooItem');

该方法的优点在于简单:Foo不需要实现自己的发布/订阅接口——事实上,如果Foo已经存在于您的应用程序中,您可以轻松地放弃此功能。另一方面,如果您没有事件订阅者,则没有任何缺点。

一些可以改进的地方:

  • 返回值的能力可能很有用,允许中断方法执行或修改发布者发送的参数。但是,由于每个主题可能有多个处理程序,因此很难实现一个简单的接口。
  • 异常处理。在大多数情况下,您可能不希望方法执行因订阅者引发异常而停止。但是,您仍然需要一些方法来报告此类错误。

我很高兴看到可以将其用于什么用途;如果您开始使用它,请给我留言!

更新(2008-12-30):根据对这篇文章的一些评论,我创建了Phly_PubSub_Provider,这是一个可以绑定的非静态实现到各个类——基本上提供了一个针对每个对象的插件系统。用法如下:

class Foo
{
    protected $_plugins;

    public function __construct()
    {
        $this->_plugins = new Phly_PubSub_Provider();
    }

    public function getPluginProvider()
    {
        return $this->_plugins;
    }

    public function bar()
    {
        $this->_plugins->publish('bar');
    }
}

$foo = new Foo();

// Subscribe echo() to the 'bar' event:
$foo->getPluginProvider()->subscribe('bar', 'echo');

$foo->bar(); // echo's 'bar'
未经允许不得转载:我爱分享网 » 一个简单的 PHP 发布-订阅系统

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏