EventDispatcher组件

编辑该页面

警告:你浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 4.3,不再维护。

这个页面的更新版本Symf欧宝娱乐app下载地址ony 6.2(当前的稳定版本)。

EventDispatcher组件

EventDispatcher组件提供了工具,让你的应用程序组件相互通信调度事件,听他们。

介绍

面向对象的代码已经很长一段路要保证代码的可扩展性。通过创建类,有明确的责任,你的代码变得更加灵活,开发人员可以使用子类扩展他们修改他们的行为。但是如果他们想要与其他开发人员共享的变化也有自己的子类,代码继承不再是答案。

考虑到现实世界的例子,你想为你的项目提供一个插件系统。插件可以添加方法,或做一些之前或之后执行一个方法,而不干扰其他插件。这不是一个容易解决的问题与单继承,即使使用PHP多重继承是可能的,它有它自己的缺点。

Symf欧宝娱乐app下载地址ony的EventDispatcher组件实现中介观察者设计模式,使所有这些东西,让你真正可扩展的项目。

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

  • 一个侦听器(PHP对象)讲述了一个中央调度程序对象,它想听kernel.response事件;
  • 在某些时候,Symfony内核告诉欧宝娱乐app下载地址调度程序对象来调度kernel.response事件,通过一个事件访问的对象响应对象;
  • 调度员通知(即调用一个方法)的所有听众kernel.response事件,让他们每个人修改响应对象。

安装

1
美元作曲家需要symfony /事件分欧宝娱乐app下载地址配器

请注意

如果你安装这个组件之外的Symfony应用程序,你必须要求欧宝娱乐app下载地址供应商/ autoload.php文件在你的代码,使作曲家提供的类加载机制。读这篇文章为更多的细节。

使用

另请参阅

这篇文章解释了如何使用EventDispatcher功能作为一个独立的组件在任何PHP应用程序。读了事件和事件监听器文章在Symfony应用程序了解如何使用它。欧宝娱乐app下载地址

事件

事件时,由一个唯一的名称(如标识。kernel.response),任意数量的听众可能听。一个事件实例也创造并传递给所有的听众。稍后您将看到,事件对象本身通常包含的数据事件被派出。

命名约定

独特的事件名称可以是任何字符串,但是选择遵循一些命名约定:

  • 只使用小写字母、数字、点()和下划线(_);
  • 前缀名称和名称空间的一个点(如紧随其后。订单。*,用户。*);
  • 终端名称动词,表示已经采取行动(如。order.placed)。

事件名称和事件对象

当调度员通知监听器,它通过一个实际的事件侦听器对象。基地事件类包含一个方法阻止事件传播,但别的就没什么了。

另请参阅

读作“通用事件对象“关于这个基础事件对象的更多信息。

通常,数据对一个特定的事件需要传递的事件对象,这样听众所需的信息。在这种情况下,一个特殊的子类,额外的方法来检索和调度时首要的信息可以通过一个事件。例如,kernel.response使用一个事件ResponseEvent,其中包含方法获得,甚至取代响应对象。

分配器

分配器是中央对象事件的调度系统。一般来说,创建一个调度程序,维护一个侦听器注册。事件时派出通过分配器,它通知所有事件监听器注册:

1 2 3
使用欧宝娱乐app下载地址\组件\EventDispatcher\EventDispatcher;美元调度程序=EventDispatcher ();

连接监听器

利用现有的事件,你需要将一个侦听程序连接到调度程序,这样就可以将通知事件。调用调度程序addListener ()方法将任何有效的PHP调用一个事件:

1 2
美元侦听器=AcmeListener ();美元调度程序- >addListener (“acme.foo.action”,(美元侦听器,“onFooAction”]);

addListener ()方法有三个参数:

  1. 事件名称(字符串),这个听者想听;
  2. 一个PHP调用时将执行指定的事件是派遣;
  3. 一个可选的重点,定义为一个积极的还是消极的整数(违约0)。数越高,早期的侦听器。如果两个听众有相同的优先级,他们的顺序执行添加到调度员。

请注意

一个PHP调用是一个PHP变量,可以使用的吗call_user_func ()函数并返回真正的当传递给is_callable ()函数。它可以是一个关闭\实例中,一个对象实现__invoke ()方法(实际上就是闭包),代表一个字符串代表一个函数或一个数组对象方法或类方法。

到目前为止,您已经看到如何将PHP对象注册为听众。你也可以注册PHP闭包事件监听器:

1 2 3 4 5
使用欧宝娱乐app下载地址\合同\EventDispatcher\事件;美元调度程序- >addListener (“acme.foo.action”,函数(事件美元事件){/ /将acme.foo时执行。动作事件派遣});

一旦一个侦听器注册的调度程序,它将等待事件通知。在上面的例子中,当acme.foo.action事件分派,分派器调用AcmeListener: onFooAction ()方法和通过了事件对象作为一个参数:

1 2 3 4 5 6 7 8 9 10 11
使用欧宝娱乐app下载地址\合同\EventDispatcher\事件;AcmeListener{/ /……公共函数onFooAction(事件美元事件){/ /……做某事}}

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

注册服务定义和标签的kernel.event_listenerkernel.event_subscriber标签不足以使事件监听器和事件订阅者。你必须注册一个编译器通过调用RegisterListenersPass ()在容器建造者:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
使用欧宝娱乐app下载地址\组件\DependencyInjection\ContainerBuilder;使用欧宝娱乐app下载地址\组件\DependencyInjection\ParameterBag\ParameterBag;使用欧宝娱乐app下载地址\组件\DependencyInjection\参考;使用欧宝娱乐app下载地址\组件\EventDispatcher\DependencyInjection\RegisterListenersPass;使用欧宝娱乐app下载地址\组件\EventDispatcher\EventDispatcher;美元containerBuilder=ContainerBuilder (ParameterBag ());/ /注册编译器通过处理“kernel.event_listener”/ /和内核。事件_订阅者' service tags美元containerBuilder- >addCompilerPass (RegisterListenersPass ());美元containerBuilder- >注册(“event_dispatch”,EventDispatcher::类);/ /注册一个事件侦听器美元containerBuilder- >注册(“listener_service_id”,\ AcmeListener::类)- >addTag (“kernel.event_listener”,(“事件”= >“acme.foo.action”,“方法”= >“onFooAction”]);/ /注册事件订阅者美元containerBuilder- >注册(“subscriber_service_id”,\ AcmeSubscriber::类)- >addTag (“kernel.event_subscriber”);

默认情况下,听众通过假定事件调度器的服务idevent_dispatch的事件监听器kernel.event_listener标签和事件的用户kernel.event_subscriber标签。您可以更改这些默认值通过自定义值的构造函数RegisterListenersPass

创建和分派事件

除了与现有事件登记侦听器,您可以创建和分派自己的事件。这是非常有用的在创建第三方库,也当你想保持自己的系统的不同组件灵活和分离。

创建一个事件类

假设您希望创建一个新的事件order.placed——这是派遣每次客户订单产品与您的应用程序。当调度这个事件时,你会通过一个定制的事件实例访问放置订单。首先创建这个定制事件类和记录:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日24日25
名称空间Acme\商店\事件;使用Acme\商店\订单;使用欧宝娱乐app下载地址\合同\EventDispatcher\事件;/ * * *订单。把每次事件派遣*系统中创建一个订单。* /OrderPlacedEvent扩展事件{公共常量NAME =“order.placed”;受保护的美元订单;公共函数__construct(订单美元订单){美元- >订单=美元订单;}公共函数getOrder(){返回美元- >秩序;}}

每个侦听器已获得通过getOrder ()方法。

请注意

如果你不需要任何额外的数据传递到事件侦听器,您还可以使用默认值事件类。在这种情况下,您可以记录事件和它的名字在一个通用的StoreEvents类,类似KernelEvents类。

调度事件

调度()方法通知所有给定事件的侦听器。它需要两个参数:事件实例传递给每个侦听器的事件和事件调度的名称:

1 2 3 4 5 6 7 8 9 10
使用Acme\商店\事件\OrderPlacedEvent;使用Acme\商店\订单;/ /订单创建或检索美元订单=订单();/ /……/ /创建OrderPlacedEvent和分派美元事件=OrderPlacedEvent (美元订单);美元调度程序- >调度(美元事件,OrderPlacedEvent::的名字);

注意,特别OrderPlacedEvent创建对象并传递到调度()方法。现在,任何侦听器order.placed事件将会收到OrderPlacedEvent

使用事件订阅者

听一个事件最常见的方法是注册一个事件监听器调度程序。此侦听器可以听一个或多个事件和通知每次派遣这些事件。

听事件的另一种方法是通过一个事件订阅者。事件订阅是一个PHP类,能够确切地告诉调度员,事件应该订阅。它实现了EventSubscriberInterface接口,这就需要一个静态方法调用getSubscribedEvents ()。采取以下一个订户订阅的例子kernel.responseorder.placed事件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35
名称空间Acme\商店\事件;使用Acme\商店\事件\OrderPlacedEvent;使用欧宝娱乐app下载地址\组件\EventDispatcher\EventSubscriberInterface;使用欧宝娱乐app下载地址\组件\HttpKernel\事件\ResponseEvent;使用欧宝娱乐app下载地址\组件\HttpKernel\KernelEvents;StoreSubscriber实现了EventSubscriberInterface{公共静态函数getSubscribedEvents(){返回[KernelEvents::响应= > [[“onKernelResponsePre”,10]、[“onKernelResponsePost”,-10年),),OrderPlacedEvent::NAME = >“onStoreOrder”,);}公共函数onKernelResponsePre(ResponseEvent美元事件){/ /……}公共函数onKernelResponsePost(ResponseEvent美元事件){/ /……}公共函数onStoreOrder(OrderPlacedEvent美元事件){/ /……}}

这非常类似于一个侦听器类,除了类本身可以告诉调度员事件应该听。与调度程序,注册一个用户使用addSubscriber ()方法:

1 2 3 4 5
使用Acme\商店\事件\StoreSubscriber;/ /……美元订阅者=StoreSubscriber ();美元调度程序- >addSubscriber (美元订阅者);

调度程序将自动返回的每个事件的注册用户getSubscribedEvents ()方法。这个方法返回一个数组索引的事件名称和值是方法名称调用或一个数组组成的方法名调用和优先级(默认为正的或负的整数0)。

上面的例子展示了如何在用户注册多个侦听器方法相同的事件,也显示了如何通过每个侦听器方法的优先级。数越高,越早的方法。在上面的例子中,当kernel.response事件触发的方法onKernelResponsePre ()onKernelResponsePost ()被称为这个顺序。

停止事件流/传播

在某些情况下,可能有一个侦听器,以防止其他听众被称为。换句话说,听者必须能够告诉调度员停止所有传播未来的事件侦听器(即不再通知侦听器)。这可以从一个侦听器通过内部完成stopPropagation ()方法:

1 2 3 4 5 6 7 8
使用Acme\商店\事件\OrderPlacedEvent;公共函数onStoreOrder(OrderPlacedEvent美元事件){/ /……美元事件- >stopPropagation ();}

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

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

1 2 3 4 5
/ /……美元调度程序- >调度(美元事件,“foo.event”);如果(美元事件- >isPropagationStopped ()) {/ /……}

EventDispatcher了解事件和监听器

EventDispatcher总是通过派遣事件,事件名称和引用自己的听众。这可能导致一些高级的应用程序EventDispatcher包括调度其他事件监听器内部,链接事件甚至延迟加载听众到分配器对象中。

事件名自省

EventDispatcher实例,以及发运的事件名称,作为参数传递给侦听器:

1 2 3 4 5 6 7 8 9 10
使用欧宝娱乐app下载地址\合同\EventDispatcher\事件;使用欧宝娱乐app下载地址\合同\EventDispatcher\EventDispatcherInterface;喷火{公共函数myEventListener(事件美元事件,美元eventName,EventDispatcherInterface美元调度程序){/ /……做一些与事件的名字吗}}

其他调度程序

除了常用的EventDispatcher组件与其他调度程序:

这项工作,包括代码示例,许可下Creative Commons冲锋队3.0许可证。