EventDispatcher组件

EventDispatcher组件

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

介绍

面向对象的代码在确保代码可扩展性方面走了很长的路。通过创建定义良好的职责的类,您的代码变得更加灵活,开发人员可以通过子类扩展它们来修改它们的行为。但是,如果他们希望与其他已经创建了自己子类的开发人员共享更改,那么代码继承就不再是答案了。

考虑一个真实的例子,您希望为您的项目提供一个插件系统。一个插件应该能够添加方法,或者在一个方法被执行之前或之后做一些事情,而不干扰其他插件。用单一继承来解决这个问题并不容易,即使用PHP可以实现多个继承,它也有自己的缺点。

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

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

  • 一种听众(PHP对象)告诉中心调度员它想要倾听的对象kernel.response.事件;
  • 在某些时候,Symfony Kerne欧宝娱乐app下载地址l告诉了调度员对象来分派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实例也被创建并传递给所有侦听器。因为你稍后会看到的事件对象本身通常包含正在调度的事件的数据。

命名约定

唯一的事件名称可以是任何字符串,但可选地遵循几个命名约定:

  • 仅使用小写字母,数字,点()和下划线(_);
  • 前缀名称后跟一个点(例如。订单。*用户。*);
  • 具有动词的终端名称,表示已经采取了哪些操作(例如order.placed)。

事件名称和事件对象

当调度员通知侦听器时,它会传递实际事件对象到那些听众。基地事件类包含用于停止的方法事件传播但除此之外就没什么了。

也可以看看

读作“通用事件对象“有关此基本事件对象的更多信息。

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

调度员

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

使用欧宝娱乐app下载地址Symfony \ \ EventDispatcher \ EventDispatcher组件;美元的调度员=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事件时执行});

侦听器在Dispatcher注册后,它会等待在通知事件之前。在上面的例子中,当acme.foo.action派遣派遣,调度员呼叫AcmeListener: onFooAction ()方法并通过事件对象作为单个参数:

使用欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;班级Acmelistener.{/ /……上市函数onfooaction.事件$赛事{/ /……做某事}}

$赛事参数是在调度事件时传递的事件对象。在许多情况下,使用额外信息传递特殊事件子类。您可以检查每个事件的文档或实现以确定欧宝体育电话传递了哪些实例。

创建和调度活动

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

创建一个事件类

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

名称空间Acme \商店\事件;使用Acme \商店\秩序;使用欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;/ * **每次创建订单时都会调度Order.Placed事件*在系统中。* /班级OrderPlacedEvent.延伸事件{上市const的名字=“order.placed”;保护美元的订单;上市函数__构造命令美元的订单{$这一点->命令=美元的订单;}上市函数getOrder()命令{返回$这一点->命令;}}

每个侦听器现在都可以通过getOrder()方法。

笔记

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

派遣事件

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

使用Acme \ Store \ Event \ OrderPlacedEvent;使用Acme \商店\秩序;//订单是以某种方式创建或检索美元的订单=命令();/ /……//创建OrderplacedEvent并调度它$赛事=OrderPlacedEvent.美元的订单);美元的调度员->派遣$赛事OrderPlacedEvent.::的名字);

请注意特别的OrderPlacedEvent.对象是创建并传递给的派遣()方法。现在,任何听众order.placed活动将收到OrderPlacedEvent.

使用活动订阅者

倾听事件的最常见方法是注册一个活动侦听器调度程序。该侦听器可以侦听一个或多个事件,并在每次调度这些事件时得到通知。

通过一个倾听事件的另一种方法是通过活动订阅者。事件订户是一个能够准确地告诉调度程序所订阅的事件的PHP类。它实现了这一点欧宝娱乐app下载地址symfony \ component \ enceDispatcher \ eventsubscriberInterface接口,它需要调用单个静态方法getSubscribedEvents()。采取订阅者的以下示例kernel.response.order.placed活动:

名称空间Acme \商店\事件;使用Acme \ Store \ Event \ OrderPlacedEvent;使用欧宝娱乐app下载地址symfony \ component \ enceDispatcher \ eventsubscriberInterface;使用欧宝娱乐app下载地址Symfony \组件\ HttpKernel \ \ ResponseEvent事件;使用欧宝娱乐app下载地址symfony \ component \ httpkernel \ kernelevents;班级Storesubscriber.实施EventSubscriberInterface{上市静止的函数getsubscribedEvents.(){返回[内科特::响应=>[['onkernelresponsepre'10],[“onKernelResponsePost”-10],],OrderPlacedEvent.::的名字=>'onstoreorder'];}上市函数onkernelresponsepte.响应$赛事{/ /……}上市函数onkernelresponsepost.响应$赛事{/ /……}上市函数在storeorder.OrderPlacedEvent.$赛事{/ /……}}

这与侦听器类非常相似,除了类本身可以告诉调度程序它应该收听的事件。要使用调度程序注册用户,请使用addSubscriber ()方法:

使用Acme \ Store \ Event \ StoreBscriber;/ /……$用户=Storesubscriber.();美元的调度员->addsubscriber.$用户);

控件返回的每个事件,调度程序将自动注册订阅者getSubscribedEvents()方法。此方法返回由事件名称索引的数组,其值是调用的方法名称或由呼叫的方法名称组成的数组(默认为的正面或负整数)0.)。

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

停止事件流/传播

在某些情况下,侦听器阻止任何其他侦听器被调用是有意义的。换句话说,侦听器需要能够告诉调度程序停止向未来的侦听器传播事件(即不通知任何其他侦听器)。这可以从侦听器内部通过stopPropagation ()方法:

使用Acme \ Store \ Event \ OrderPlacedEvent;上市函数在storeorder.OrderPlacedEvent.$赛事{/ /……$赛事->stopPropagation();}

现在,任何听众order.placed尚未被称为意志不是被称为。

方法可以检测事件是否停止ispropagationstopped()方法返回一个布尔值:

/ /……美元的调度员->派遣$赛事“foo.event”);如果$赛事->isPropagationStopped()){/ /……}

EventDispatcher感知事件和监听器

EventDispatcher始终通过调度事件,事件的名称和对侦听器的引用。这可以导致一些高级应用EventDispatcher包括调度侦听器中的其他事件,链接事件甚至延迟将侦听器甚至进入Dispatcher对象。

事件名称内省

EventDispatcher实例,以及已调度的事件的名称,作为侦听器的参数传递:

使用欧宝娱乐app下载地址Symfony \ Contracts \ EventDispatcher \ Event;使用欧宝娱乐app下载地址symfony \ contracts \ enceDispatcher \ enceDispatcherInterface;班级Foo{上市函数myEventListener事件$赛事$ eventName.EventDispatcherInterface美元的调度员{// ...用事件名称做点什么}}

其他调度员

除了常用的EventDispatcher,该组件附带其他一些调度员:

这项工作包括代码样本,是在a下获得的许可Creative Commons by-SA 3.0执照。