我在 Symfony2 框架中工作,想知道什么时候会使用 Doctrine 订阅者而不是侦听器。Doctrine 的听众文档非常清晰,但订阅者却被掩盖了。Symfony 的食谱条目是类似的。
7 回答
在我看来,只有一个主要区别:
- 侦听器已注册,指定它侦听的事件。
- 订阅者有一个方法告诉调度者它正在监听什么事件
这可能看起来没什么大区别,但如果你仔细想想,在某些情况下你想使用一个而不是另一个:
- 您可以将一个侦听器分配给具有不同事件的多个调度程序,因为它们是在注册时设置的。您只需要确保每个方法都在侦听器中就位
- 您可以更改订阅者在运行时注册的事件,甚至在注册订阅者之后通过更改返回值
getSubscribedEvents
(想想有一次您收听一个非常嘈杂的事件并且您只想执行一次)
可能还有其他我不知道的差异!
不知道这是意外还是故意..但订阅者的优先级高于听众 - https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass .php#L73-L98
从学说方面,它不在乎它是什么(监听器或订阅者),最终两者都注册为监听器 - https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/EventManager.php #L137-L140
这是我发现的。
当你想在一个类中处理多个事件时,你应该使用事件订阅者,例如在这个symfony2 文档页面文章中,人们可能会注意到事件监听器只能管理一个事件,但是假设你想为一个实体处理多个事件,prePersist、preUpdate、postPersist 等......如果你使用事件监听器,你将不得不编写几个事件监听器,每个事件一个,但是如果您使用事件订阅者,您只需为事件订阅者编写一个类,看看使用事件订阅者您可以在一个类中管理多个事件,这就是我使用它的方式,我更喜欢要专注于模型业务需要的代码,一个示例可能是您只想为一组实体在全局范围内处理多个生命周期事件,为此您可以编写父类并在其中定义这些全局方法,然后让您的实体继承该类,然后在您的事件订阅者中订阅您想要的每个事件,prePersist,preUpdate、postPersist 等......然后请求该父类并执行这些全局方法。
另一件重要的事情:Doctrine EventSubscribers 不允许您设置优先级。
在此处阅读有关此问题的更多信息
两者都允许您在特定事件前/后持久等上执行某些操作。
然而,监听器只允许你执行封装在你的实体中的行为。因此,一个示例可能是更新“date_edited”时间戳。
如果您需要移出实体的上下文,那么您将需要一个订阅者。一个很好的例子可能是调用外部 API,或者如果您需要使用/检查与您的实体不直接相关的数据。
这是文档在 4.1 中所说的内容。由于这在全球范围内适用于事件,我想它对 Doctrine 也有效(不是 100% 肯定)。
听众或订阅者
侦听器和订阅者可以在同一个应用程序中模糊地使用。使用其中任何一个的决定通常取决于个人喜好。但是,它们每个都有一些小优点:
- 订阅者更容易重用,因为事件的知识保存在类中而不是服务定义中。这就是 Symfony 在内部使用订阅者的原因。
- 侦听器更灵活,因为捆绑可以根据某些配置值有条件地启用或禁用每个侦听器。
http://symfony.com/doc/master/event_dispatcher.html#listeners-or-subscribers
从文档中:
侦听事件的最常见方法是向调度程序注册事件侦听器。此侦听器可以侦听一个或多个事件,并在每次调度这些事件时收到通知。
另一种监听事件的方法是通过事件订阅者。事件订阅者是一个 PHP 类,它能够准确地告诉调度程序它应该订阅哪些事件。它实现了 EventSubscriberInterface 接口,该接口需要一个名为 getSubscribedEvents() 的静态方法。
请参阅此处的示例:
https://symfony.com/doc/3.3/components/event_dispatcher.html