首页 > 文章列表 > 使用Symfony事件调度器来处理PHP事件

使用Symfony事件调度器来处理PHP事件

PHP事件处理 Symfony事件调度器 事件调度
416 2023-09-04

今天,我们将学习如何使用 Symfony 事件调度程序组件,它允许您在 PHP 应用程序中创建事件和侦听器。因此,应用程序的不同组件可以通过松散耦合的代码相互通信。

什么是 Symfony 事件调度程序组件?

您可能熟悉事件观察者模式,它允许您为系统生成的事件定义侦听器,以便在触发事件时执行它们。类似地,Symfony EventDispatcher 组件允许您设置一个可以在其中创建自定义事件和侦听器的系统。通过这种方式,您允许应用程序中的组件在系统中发生某些事情时做出反应。

事实上,事件调度程序组件提供了三个元素,您可以围绕它们构建应用架构:事件、侦听器和调度程序。整个系统由调度程序类编排,该类在应用程序中的适当点引发事件并调用与这些事件关联的侦听器。

假设您希望允许应用程序中的其他组件在缓存被清除时做出反应。在这种情况下,您需要首先定义清除缓存事件。清除缓存后,您可以使用调度程序引发清除缓存事件,并通知所有正在侦听此事件的侦听器。这使侦听器有机会清除特定于组件的缓存。

在本文中,我们将探讨事件调度程序组件的基础知识。我们将从安装和配置开始,我们还将创建一些实际示例来演示上述所有概念。

安装和配置事件调度程序

在本节中,我们将安装事件调度程序组件。我假设您已经在系统上安装了 Composer,因为我们需要它来安装 EventDispatcher 组件。

安装 Composer 后,请继续使用以下命令安装 EventDispatcher 组件。

$composer require symfony/event-dispatcher

这应该创建了 composer.json 文件,它应该如下所示:

{
    "require": {
        "symfony/event-dispatcher": "^5.4"
    }
}

让我们进一步编辑 composer.json 文件,如下所示:

{
    "require": {
        "symfony/event-dispatcher": "^5.4"
    },
    "autoload": {
         "psr-4": {
             "EventDispatchers\": "src"
         },
         "classmap": ["src"]
     }
}

由于我们添加了新的类映射条目,因此请继续运行以下命令来更新 Composer 自动加载器。

$composer dump -o

现在,您可以使用 EventDispatchers 命名空间来自动加载 src 目录下的类。

这就是安装部分,但是你应该如何使用它呢?事实上,只需将 Composer 创建的 autoload.php 文件包含在您的应用程序中即可,如以下代码片段所示。

<?php
require_once './vendor/autoload.php';
 
// application code
?>

如何创建、调度和侦听事件

在本节中,我们将通过一个示例来演示如何创建自定义事件并为该事件设置侦听器。

事件类

首先,继续创建包含以下内容的 src/Events/DemoEvent.php 文件。

<?php
namespace EventDispatchersEvents;
 
use SymfonyContractsEventDispatcherEvent;
 
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。当您想要为此事件设置侦听器时使用它。

监听器类

接下来,让我们使用以下内容创建监听器类src/Listeners/DemoListener.php

<?php
namespace EventDispatchersListeners;
 
use SymfonyContractsEventDispatcherEvent;
 
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 事件时触发。当然,这还不会自动发生,因为我们需要注册 DemoListener 监听器,以使用 EventDispatcher 类来监听 demo.event 事件。

到目前为止,我们已经创建了事件和侦听器类。接下来,我们将了解如何将所有这些部分连接在一起。

示例文件

让我们创建包含以下内容的 basic_example.php 文件。

<?php
// basic_example.php
 
require_once './vendor/autoload.php';
use SymfonyComponentEventDispatcherEventDispatcher;
use EventDispatchersEventsDemoEvent;
use EventDispatchersListenersDemoListener;
 
// 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 类的 dispatch 方法来调度 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 方法,进而调用 getFoo 方法= "inline">DemoEvent 类来获取事件相关信息。

什么是事件订阅者?

在上一节中,我们构建了一个示例,演示了如何创建自定义事件和自定义侦听器。我们还讨论了如何使用 EventDispatcher 类将侦听器绑定到特定事件。

这是一个简单的示例,因为我们只想为单个事件设置侦听器。另一方面,如果您想要为多个事件设置侦听器,或者想要在逻辑上将事件处理逻辑分组到单个类中,则应该考虑使用事件订阅者,因为它们允许您将所有内容保留在一个位置。

在本节中,我们将修改上一节中创建的示例。

订阅者类别

我们需要做的第一件事是创建一个实现 EventSubscriberInterface 接口的订阅者类。继续创建 src/Subsribers/DemoSubscriber.php 类,如以下代码片段所示。

<?php
namespace EventDispatchersSubscribers;
 
use SymfonyComponentEventDispatcherEventSubscriberInterface;
use EventDispatchersEventsDemoEvent;
 
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_example.php 文件。

<?php
require_once './vendor/autoload.php';
use SymfonyComponentEventDispatcherEventDispatcher;
use EventDispatchersSubscribersDemoSubscriber as DemoSubscriber;
use EventDispatchersEventsDemoEvent;
 
// 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

这就是您可以使用的事件订阅者!这也让我们进入了本文的结尾。

如何停止事件传播

有时,多个侦听器正在侦听同一事件。在这种情况下,您可能希望停止将事件传播到下一个后续侦听器。在本节中,我们将了解如何在侦听器的帮助下实现这一目标。

让我们回顾一下之前创建的侦听器类。

<?php
namespace EventDispatchersListeners;
 
use SymfonyContractsEventDispatcherEvent;
 
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 对象。

让我们快速修改一下前面的示例。

<?php
require_once './vendor/autoload.php';
use SymfonyComponentEventDispatcherEventDispatcher;
use EventDispatchersEventsDemoEvent;
 
// 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 应用程序中设置事件和侦听器。通过使用此库,您可以创建一个松散耦合的系统,该系统允许应用程序的组件轻松地相互通信。