EventDispatcher组件

5.3版本
欧宝娱乐app下载地址symfony 5.3支持经过JoliCode

EventDispatcher组件

EventDispatcher组件提供了一些工具,这些工具允许应用程序组件通过分派事件和监听事件来相互通信。

介绍

面向对象的代码已经有很长的路要能确保代码可扩展性。通过创建具有明确定义责任的类,您的代码变得更灵活,开发人员可以使用子类扩展它们来修改其行为。但是,如果他们想与其他开发人员分享那些也完成自己的子类的其他开发人员,则代码继承不再是答案。

考虑您想要为项目提供插件系统的真实界面。插件应该能够添加方法,或者在执行方法之前或之后做某事,而不会干扰其他插件。通过单一继承解决,这不是一个简单的问题,即使使用PHP可能进行多种继承,它也会附带自己的缺点。

Symf欧宝娱乐app下载地址ony EventDispatcher组件实现了介质观察者设计模式,使所有这些事情成为可能,并使您的项目真正可扩展。

举例httpkernel组件.一旦响应对象已经被创建,在它被实际使用之前,允许系统中的其他元素修改它(例如添加一些缓存头)可能是有用的。为了使这成为可能,Symfony内核会抛出一个事件-欧宝娱乐app下载地址kernel.response.这是它的工作原理:

  • 一种听众(PHP对象)讲述一个中心调度员对象,它希望侦听kernel.response事件;
  • 在某种程度上,Symfony内核告诉欧宝娱乐app下载地址调度员派遣的对象kernel.response事件,通过它事件对象的响应目的;
  • 调度员通知(即呼叫方法)所有侦听器kernel.response事件,允许他们中的每一个对其进行修改响应目的。

安装

1
$Composer需要Symfony欧宝娱乐app下载地址 / Event-Dispatcher

笔记

如果在Symfony应用程序之外安装此组件,则必须要求欧宝娱乐app下载地址供应商/ autoload.php.以启用Composer提供的类自动加载机制。读这篇文章更多细节。

用法

也可以看看

本文介绍了如何在任何PHP应用程序中使用EventDispatcher功能作为独立组件。阅读活动和活动听众文章学习如何在Symfony应用程序中使用它。欧宝娱乐app下载地址

活动

当一个事件被分派时,它将被唯一的名称标识(例如。kernel.response),任何数量的听众都可能在听。一个欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event实例也被创建并传递给所有侦听器。稍后您将看到事件对象本身通常包含有关正在分派的事件的数据。

命名惯例

唯一的事件名可以是任何字符串,但可以遵循一些命名约定:

  • 仅使用小写字母,数字,点()和下划线(_);
  • 前缀名称后跟一个点(例如。命令。*用户。*);
  • 以动词结尾,表示已经采取了什么行动。订单已下)。

事件名称和事件对象

当调度员通知侦听器时,它会传递实际事件对象到那些听众。基地事件类包含一种停止方法事件传播,但并不需要其他。

也可以看看

读 ”通用事件对象获取有关此基本事件对象的更多信息。

通常,有关特定事件的数据需要与之传递事件对象使听众具有所需的信息。在这种情况下,可以在调度事件时传递具有用于检索和覆盖信息的附加方法的特殊子类。例如,kernel.response活动使用A.欧宝娱乐app下载地址symfony \ component \ httpkernel \事件\ responseavent,其中包含获取甚至替换响应目的。

分配器

调度程序是事件调度程序系统的核心对象。通常,创建单个调度程序,该调度程序维护侦听器的注册表。当通过调度程序调度事件时,它会通知所有侦听器在该事件中注册:

欧宝娱乐app下载地址symfony \ component \ enceDispatcher \ enceDispatcher;$调度员=新的EventDispatcher.();

连接听众

为了利用现有事件,您需要将侦听器连接到调度程序,以便在发送事件时可以通知它。对Dispatcher的调用AddListener()方法将任何有效的PHP可调用对象关联到一个事件:

$倾听者=新的AcmeListener();$调度员- >addListener.'acme.foo.action'[$倾听者'onfooaction']);

AddListener()方法最多需要三个参数:

  1. 这个侦听器想要收听的事件名称(字符串);
  2. 在调度指定的事件时将执行的PHP可调用;
  3. 可选的优先级,定义为正或负整数(默认为0.)。数量越高,侦听器的较早。如果两个侦听器具有相同的优先级,则按向调度程序添加到调度程序的顺序执行它们。

笔记

一种PHP调用是一个PHP变量,可以被call_user_func()功能和返回真的当传递到is_callable ()函数。它可以是\关闭实例,实现一个对象__invoke()方法(这是闭包的事实上),表示表示对象方法或类方法的函数或数组的字符串。

到目前为止,您已经看到了PHP对象如何注册为侦听器。您还可以注册PHP关闭作为活动听众:

欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;$调度员- >addListener.'acme.foo.action'功能事件美元的事件{//将在派遣acme.foo.action事件时执行});

一旦向调度程序注册了侦听器,它就会一直等待,直到事件得到通知。在上面的例子中,当Acme.foo.action.派遣派遣,调度员呼叫Acmelistener :: onfooaction()方法并通过事件对象作为单个参数:

欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;班级AcmeListener{/ /……公共功能onFooAction事件美元的事件{/ /……做某事}}

美元的事件参数是在分派事件时传递的事件对象。在许多情况下,一个特殊的事件子类与额外的信息一起被传递。您可以检查每个事件的文档或实现,以确欧宝体育电话定传递了哪个实例。

创建和分发事件

除了用现有事件注册监听器之外,您还可以创建和分派自己的事件。这在创建第三方库时很有用,在您希望保持自己系统的不同组件的灵活性和解耦性时也很有用。

创建一个事件类

假设您想创建一个新事件 -订单已下- 每次客户订购产品时都会调度。调度此事件时,您将通过可访问已放置订单的自定义事件实例。首先创建此自定义事件类并记录它:

名称空间acme \ store \活动;ACME \ Store \订单;欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;/ ***每次创建订单时都会调度Order.Placed事件*在系统中。* /班级OrderPlacedEvent扩展事件{公共常量名称='订单已下';保护$订单;公共功能__构造订单$订单{这个美元- >命令=$订单;}公共功能getOrder.()订单{返回这个美元- >命令;}}

每个侦听器现在都通过通过该侦听器访问订单getOrder()方法。

笔记

如果您不需要将任何其他数据传递给事件侦听器,您也可以使用默认值欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event班级。在这种情况下,您可以在通用中记录事件及其名称StoreEvents类,类似于欧宝娱乐app下载地址Symfony \ \ HttpKernel \ KernelEvents组件班级。

调度事件

派遣()方法通知给定事件的所有侦听器。需要两个论点:事件实例传递给该事件的每个监听器和要分派的事件的名称:

Acme \商店\ \ OrderPlacedEvent事件;ACME \ Store \订单;//以某种方式创建或检索订单$订单=新的订单();/ /……//创建OrderplacedEvent并调度它美元的事件=新的OrderPlacedEvent$订单);$调度员- >派遣美元的事件OrderPlacedEvent::名称);

注意这个特殊的OrderPlacedEvent对象是创建并传递给的派遣()方法。现在,任何倾听者订单已下活动将收到OrderPlacedEvent

使用活动订阅者

倾听事件的最常见方法是注册一个活动侦听器随时随地。此侦听器可以收听一个或多个事件,每次调度这些事件时都会通知。

通过一个倾听事件的另一种方法是通过事件订阅者.事件订阅者是一个PHP类,它能够确切地告诉调度程序应该订阅哪些事件。它实现了欧宝娱乐app下载地址Symfony \ \ EventDispatcher \ EventSubscriberInterface组件接口,需要一个静态方法调用getSubscribedEvents().采取订阅者的以下示例kernel.response订单已下事件:

名称空间acme \ store \活动;Acme \商店\ \ OrderPlacedEvent事件;欧宝娱乐app下载地址Symfony \ \ EventDispatcher \ EventSubscriberInterface组件;欧宝娱乐app下载地址symfony \ component \ httpkernel \事件\ responseavent;欧宝娱乐app下载地址Symfony \ \ HttpKernel \ KernelEvents组件;班级StoreSubscriber实现了eventsubscriberInterface.{公共静止的功能getSubscribedEvents(){返回[内科特::回复=>[[“onKernelResponsePre”10.],['onkernelresponsepost'-10.],],OrderPlacedEvent::名称=>“onStoreOrder”];}公共功能onkernelresponsepte.响应美元的事件{/ /……}公共功能onKernelResponsePost响应美元的事件{/ /……}公共功能onStoreOrderOrderPlacedEvent美元的事件{/ /……}}

这与侦听器类非常相似,除了类本身可以告诉调度程序它应该侦听哪些事件。若要向调度程序注册订阅者,请使用addsubscriber()方法:

Acme \ Store \ Event \ StoreBscriber;/ /……$用户=新的StoreSubscriber();$调度员- >addSubscriber$用户);

调度员将自动注册订户的每项事件getSubscribedEvents()方法。该方法返回一个按事件名称索引的数组,其值要么是要调用的方法名,要么是由要调用的方法名和优先级(默认为正整数或负整数)组成的数组0.)。

上面的示例显示了如何在订阅者中为同一事件注册多个侦听器方法,也显示如何传递每个侦听器方法的优先级。数量越高,方法的越早调用。在上面的例子中,当kernel.response事件被触发,方法onkernelresponsepre()onKernelResponsePost ()按此顺序调用。

停止事件流/传播

在某些情况下,听众可能对阻止任何其他侦听器称为调用的意义。换句话说,侦听器需要能够告诉调度器将事件的所有传播停止到未来的侦听器(即不通知任何侦听器)。这可以通过收听者内部通过stopprojagation()方法:

Acme \商店\ \ OrderPlacedEvent事件;公共功能onStoreOrderOrderPlacedEvent美元的事件{/ /……美元的事件- >stopPropagation();}

现在,任何听众订单已下还没有被称为意志叫做。

可以通过使用该事件来检测事件是否已停止ispropagationstopped()返回布尔值的方法:

/ /……$调度员- >派遣美元的事件'foo.event');如果美元的事件- >ispropagationstopped()){/ /……}

EventDispatcher意识到事件和侦听器

EventDispatcher.总是将已分派的事件、事件的名称和对自身的引用传递给监听器。这可以导致一些先进的应用EventDispatcher.包括调度侦听器中的其他事件,链接事件甚至延迟将侦听器甚至进入Dispatcher对象。

事件名称内省

EventDispatcher.实例,以及被分派的事件的名称,作为参数传递给监听器:

欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;欧宝娱乐app下载地址Symfony \ \ EventDispatcher \ EventDispatcherInterface合同;班级Foo{公共功能MyeventListener.事件美元的事件$ eventName.EventDispatcherInterface.$调度员{/ /……对事件名做些什么}}

其他调度程序

除了常用的EventDispatcher.,该组件附带了其他一些dispatchers:

这项工作,包括代码样本,是在一个Creative Commons by-SA 3.0执照。