今天,我们将学习如何使用 Symfony 事件调度器组件,它允许我们在 PHP 应用程序中创建事件和侦听器。 因此,应用程序的不同组件可以通过松散耦合的代码相互通信。
什么是 Symfony 事件调度器组件?
我们可能熟悉事件观察者模式,它允许我们为系统生成的事件定义侦听器,以便在事件触发时执行它们。 同样,Symfony EventDispatcher
组件允许我们设置一个系统,我们可以在其中创建自定义事件和侦听器。 通过这种方式,我们可以让应用程序中的组件在系统中发生某些事情时做出反应。
事实上,事件调度器组件提供了三个元素,我们可以围绕这些元素构建应用程序架构:事件、侦听器和派发器。 整个系统由调度程序类编排,它在应用程序中的适当点引发事件并调用与这些事件关联的侦听器。
假设我们希望应用程序中的其他组件在清除缓存时做出反应。 在这种情况下,我们需要首先定义清除缓存事件。 清除缓存后,我们可以使用调度程序引发清除缓存事件,并通知所有正在侦听此事件的侦听器。 这使侦听器有机会清除特定于组件的缓存。
在本文中,我们将探讨事件分发器组件的基础知识。 我们将从安装和配置开始,我们还将创建一些真实示例来演示上述所有概念。
安装和配置事件调度程序
在本节中,我们将安装事件分发器组件。 我假设大家已经在系统上安装了 Composer,因为我们需要它来安装 EventDispatcher
组件。
安装 Composer 后,继续使用以下命令安装 EventDispatcher
组件。
$ composer require symfony/event-dispatcher
那应该已经创建了 composer.json 文件,它应该如下所示:
composer.json
{ "require": { "symfony/event-dispatcher": "^5.4" } }
让我们进一步编辑 composer.json 文件,如下所示:
composer.json
{ "require": { "symfony/event-dispatcher": "^5.4" }, "autoload": { "psr-4": { "EventDispatchers\\": "src" }, "classmap": ["src"] } }
当我们添加了一个新的类映射条目时,继续并通过运行以下命令更新 Composer 自动加载器。
$ composer dump -o
现在,我们可以使用 EventDispatchers
命名空间自动加载 src 目录下的类。
这就是安装部分,但是我们应该如何使用它呢? 事实上,这只是将 Composer 创建的 autoload.php 文件包含在您的应用程序中的问题,如以下代码段所示。
require_once './vendor/autoload.php';
// 应用程序代码
如何创建、分发和监听事件
在本节中,我们将通过一个示例演示如何创建自定义事件并为该事件设置侦听器。
Event 类
首先,继续创建具有以下内容的 src/Events/DemoEvent.php 文件。
src/Events/DemoEvent.php
namespace EventDispatchers\Events; use Symfony\Contracts\EventDispatcher\Event; class DemoEvent extends Event { const NAME = 'demo.event'; protected $foo; public function __construct() { $this->foo = 'bar'; } public function getFoo() { return $this->foo; } }
我们的自定义 DemoEvent 类扩展了 EventDispatcher
组件的核心 Event 类。 NAME 常量保存我们自定义事件的名称——demo.event。 当我们想为此事件设置侦听器时使用它。
Listener 类
接下来,让我们创建具有以下内容的监听器类 src/Listeners/DemoListener.php。
src/Listeners/DemoListener.php
namespace EventDispatchers\Listeners; use Symfony\Contracts\EventDispatcher\Event; class DemoListener { public function onDemoEvent(Event $event) { // fetch event information here echo "DemoListener is called!\n"; echo "The value of the foo is: ".$event->getFoo()."\n"; } }
DemoListener
类实现了 onDemoEvent
方法,该方法在系统调度 DemoEvent 事件时触发。 当然,它不会自动发生,因为我们需要使用 EventDispatcher
类注册 DemoListener 侦听器来侦听 demo.event 事件。
到目前为止,我们已经创建了事件和侦听器类。 接下来,我们将看看如何将所有这些部分联系在一起。
示例文件
让我们创建具有以下内容的 basic_example.php 文件。
basic_example.php
require_once './vendor/autoload.php'; use Symfony\Component\EventDispatcher\EventDispatcher; use EventDispatchers\Events\DemoEvent; use EventDispatchers\Listeners\DemoListener; // init event dispatcher $dispatcher = new EventDispatcher(); // register listener for the 'demo.event' event $listener = new DemoListener(); $dispatcher->addListener('demo.event', array($listener, 'onDemoEvent')); // dispatch $dispatcher->dispatch(new DemoEvent(), DemoEvent::NAME);
EventDispatcher 类是 EventDispatcher
组件中最重要的元素——它允许您将侦听器绑定到他们想要侦听的事件。 我们使用了 EventDispatcher 类的 addListener
方法来监听 demo.event 事件。
addListener
方法的第一个参数是在派发注册事件时触发的 PHP 可调用对象,第二个参数是事件名称。 在我们的例子中,我们提供了 DemoListener 对象作为侦听器以及 onDemoEvent
方法。
$dispatcher->addListener('demo.event', array($listener, 'onDemoEvent'));
最后,我们使用了 EventDispatcher
类的调度方法来调度 demo.event 事件。
$dispatcher->dispatch(DemoEvent::NAME, new DemoEvent());
当我们运行 basic_example.php 文件时,它应该会产生以下输出。
$ php basic_example.php
DemoListener is called!
The value of the foo is: bar
正如预期的那样,调用了 DemoListener 类的 onDemoEvent
方法,然后又调用了 DemoEvent 类的 getFoo
方法来获取与事件相关的信息。
什么是事件订阅者?
在上一节中,我们构建了一个示例,演示了如何创建自定义事件和自定义侦听器。 我们还讨论了如何使用 EventDispatcher 类将侦听器绑定到特定事件。
这是一个简单的例子,因为我们只想为单个事件设置一个监听器。 另一方面,如果我们想要为多个事件设置侦听器,或者我们想要在逻辑上将事件处理逻辑分组到一个类中,我们应该考虑使用事件订阅者,因为它们允许我们将所有内容保存在一个地方。
在本节中,我们将修改在上一节中创建的示例。
Subscriber
我们需要做的第一件事是创建一个实现 EventSubscriberInterface
接口的 Subscriber 类。 继续并创建 src/Subsribers/DemoSubscriber.php 类,如以下代码片段所示。
src/Subsribers/DemoSubscriber.php
namespace EventDispatchers\Subscribers; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use EventDispatchers\Events\DemoEvent; class DemoSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return array( DemoEvent::NAME => 'onDemoEvent', ); } public function onDemoEvent(DemoEvent $event) { // fetch event information here echo "DemoListener is called!\n"; echo "The value of the foo is :".$event->getFoo()."\n"; } }
由于 DemoSubscriber 类实现了 EventSubscriberInterface 接口,因此它必须实现 getSubscribedEvents
方法。 getSubscribedEvents
方法应返回我们要订阅的事件数组。 我们需要在数组键中提供事件名称,在触发事件时调用的数组值中提供方法名称。
最后一件事是在同一个类中实现监听器方法。 在我们的例子中,我们需要实现 onDemoEvent
方法,我们已经做到了。
示例文件
是时候测试我们的 subscriber 了! 让我们快速创建包含以下内容的 subscriber_example.php 文件。
subscriber_example.php
require_once './vendor/autoload.php'; use Symfony\Component\EventDispatcher\EventDispatcher; use EventDispatchers\Subscribers\DemoSubscriber as DemoSubscriber; use EventDispatchers\Events\DemoEvent; // init event dispatcher $dispatcher = new EventDispatcher(); // register subscriber $subscriber = new DemoSubscriber(); $dispatcher->addSubscriber($subscriber); // dispatch $dispatcher->dispatch(new DemoEvent(), DemoEvent::NAME);
我们需要使用 EventDispatcher 类的 addSubscriber
方法来订阅我们的自定义订阅者,EventDispatcher 类会处理剩下的事情。 它从 getSubscribedEvents
方法获取要订阅的事件,并为这些事件设置侦听器。 除此之外,一切都是一样的,它应该按预期工作,没有任何意外。
让我们测试一下!
$ php subscriber_example.php
DemoListener is called!
The value of the foo is: bar
那就是我们可以使用的事件订阅者! 这也将我们带到了本文的结尾。
如何停止事件传播
有时,多个侦听器正在侦听同一个事件。 在这种情况下,我们可能希望停止向下一个后续侦听器传播事件。 在本节中,我们将了解如何在侦听器的帮助下实现它。
让我们重新访问我们之前创建的侦听器类。
namespace EventDispatchers\Listeners;
use Symfony\Contracts\EventDispatcher\Event;
class DemoListener
{
public function onDemoEvent(Event $event)
{
// fetch event information here
echo "DemoListener is called!\n";
echo "The value of the foo is: ".$event->getFoo()."\n";
$event->stopPropagation();
}
}
如大家所见,我们使用了 stopPropagation
方法来停止事件传播。 这意味着正在侦听 demo.event 事件但尚未被调用的侦听器将不会被调用。 所以这是为此事件调用的最后一个侦听器。 我们还可以使用 isPropagationStopped
方法来检测事件传播是否被任何侦听器停止。
如何使用 PHP 闭包作为监听器
到目前为止,我们已经讨论了如何将 PHP 对象添加为侦听器。 事实上,我们也可以使用 PHP 闭包来代替 PHP 对象。
让我们快速修改前面的示例。
require_once './vendor/autoload.php';
use Symfony\Component\EventDispatcher\EventDispatcher;
use EventDispatchers\Events\DemoEvent;
// init event dispatcher
$dispatcher = new EventDispatcher();
// register closure listener for the 'demo.event' event
$dispatcher->addListener('demo.event', function (DemoEvent $event) {
echo "DemoListener is called!\n";
echo "The value of the foo is: ".$event->getFoo()."\n";
});
// dispatch
$dispatcher->dispatch(new DemoEvent(), 'demo.event');
如您所见,我们在 addListener
方法的第二个参数中使用了 PHP 闭包。
总结
今天,我们探索了 Symfony 事件调度器组件,它允许我们在 PHP 应用程序中设置事件和侦听器。 通过使用这个库,我们可以创建一个松散耦合的系统,允许我们的应用程序的组件毫不费力地相互通信。