【问题标题】:Doctrine Listener versus Subscriber教义听众与订阅者
【发布时间】:2012-05-30 14:48:51
【问题描述】:

我在 Symfony2 框架中工作,想知道什么时候会使用 Doctrine 订阅者而不是侦听器。 Doctrine 为听众提供的documentation 非常清楚,但订阅者却被掩盖了。 Symfony 的cookbook entry 类似。

【问题讨论】:

  • Ross Tuck 几天前在 DutchPHPConference 上进行了 Doctrine2 演讲。他还处理了 Doctrine2 中的事件,他的幻灯片在这里:slideshare.net/rosstuck/… 也许它可能对你有一些额外的信息/帮助。
  • 您自己的代码中确实不需要监听器。更详细的答案见Don't ever use Listeners

标签: symfony doctrine-orm


【解决方案1】:

来自文档:

监听事件最常见的方式是注册一个事件 调度程序的侦听器。此听众可以收听一个或多个 事件并在每次调度这些事件时得到通知。

另一种监听事件的方法是通过事件订阅者。一个事件 订阅者是一个 PHP 类,它能够准确地告诉调度员 它应该订阅哪些事件。它实现了 EventSubscriberInterface 接口,需要单个静态 方法称为 getSubscribedEvents()。

请看这里的例子:

https://symfony.com/doc/3.3/components/event_dispatcher.html

【讨论】:

    【解决方案2】:

    这是文档在 4.1 中所说的内容。 由于这在全球范围内适用于事件,我想它对 Doctrine 也有效(不是 100% 肯定)。

    听众或订阅者

    监听器和订阅者可以在同一个应用程序中模糊地使用。使用其中任何一个的决定通常是一个问题 个人口味。但是,每个都有一些小优点 其中:

    • 订阅者更容易重用,因为事件的知识保存在类中而不是服务定义中。 这是 Symfony 内部使用订阅者的原因;
    • 侦听器更加灵活,因为捆绑包可以根据某些配置值有条件地启用或禁用每个侦听器。

    http://symfony.com/doc/master/event_dispatcher.html#listeners-or-subscribers

    【讨论】:

      【解决方案3】:

      另一件重要的事情:Doctrine EventSubscribers 不允许您设置优先级。

      阅读有关此问题的更多信息here

      【讨论】:

      • 灯泡亮着。谢谢!
      • 这不是真的,除此之外,这是由 Ruslan Polutsygan 之前发布的。
      【解决方案4】:

      不知道是有意还是无意。但订阅者的优先级高于听众 - 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

      这是我发现的。

      【讨论】:

        【解决方案5】:

        当你想在一个类中处理多个事件时,你应该使用事件订阅者,例如在这个symfony2 doc page article,你可能会注意到事件监听器只能管理一个事件,但是假设你想处理多个事件对于一个实体,prePersist、preUpdate、postPersist 等...如果您使用事件侦听器,您将必须编写多个事件侦听器,每个事件一个,但如果您使用事件订阅者,您只需编写一个事件订阅者类,看起来,使用事件订阅者,您可以在一个类中管理多个事件,这就是我使用它的方式,我更喜欢专注于模型业务需要的代码,其中一个示例可能是您想要处理多个生命周期仅针对一组实体的全局事件,为此,您可以编写父类并在其中定义这些全局方法,然后使您的实体继承该类,然后在您的事件订阅者中订阅您想要的每个事件,prePersist,preUpdate , postPersist 等c... 然后请求那个父类并执行那些全局方法。

        【讨论】:

        • 我可能误解了你,但根据我的经验,Listener 可以管理多个事件,例如一个 Listener 可以为 prePersist、preUpdate、onFlush 等定义动作。
        • @ChadwickMeyer 是的,我第二次说“此侦听器可以侦听一个或多个事件,并且每次调度这些事件时都会收到通知。”直接来自文档
        【解决方案6】:

        在我看来,只有一个主要区别:

        • 监听器已注册,指定它监听的事件。
        • 订阅者有一个方法告诉调度者它正在监听什么事件

        这似乎没什么大的区别,但如果你仔细想想,在某些情况下你想使用一个而不是另一个:

        • 您可以将一个侦听器分配给具有不同事件的多个调度程序,因为它们是在注册时设置的。您只需要确保每个方法都在侦听器中就位
        • 您可以通过更改getSubscribedEvents 的返回值来更改订阅者在运行时注册的事件,甚至在注册订阅者之后(想一想您听到一个非常嘈杂的事件并且只想执行某些操作的时间)一次)

        可能还有其他我不知道的差异!

        【讨论】:

        • 那么,简而言之,订阅者就是一个监听器,监听的事件列表是可变的?在getSubscribedEvents 中,我会返回一个数组,类似于array(Events::prePersist, Events::postUpdate) 我猜?
        • @Sgoettschkes 帖子中的链接已损坏,当前喜欢的应该是 doctrine-project.org/projects/doctrine-orm/en/latest/reference/…
        • @nurikabe 我读了你的评论,很好奇 Symfony 的订阅者是否真的是可变的,turns out they aren't。订阅者只是预先配置的侦听器,在同一级别比较它们根本不完全正确。订阅者包含侦听器,但侦听器不包含或不是订阅者(在 Symfony 术语中)。
        【解决方案7】:

        两者都允许您在特定事件上执行某些事前/后持久化等。

        然而监听器只允许你执行封装在你的实体中的行为。因此,一个示例可能是更新“date_edited”时间戳。

        如果您需要移出实体的上下文,则需要订阅者。一个很好的例子可能是调用外部 API,或者如果您需要使用/检查与您的实体不直接相关的数据。

        【讨论】:

        • 我可能会误解,但这听起来像是生命周期回调和事件监听器之间的区别?我正在尝试确定何时可以使用(在 Symfony2 中)doctrine.event_subscriber 而不是 doctrine.event_listener
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-10
        • 1970-01-01
        • 1970-01-01
        • 2017-03-20
        • 1970-01-01
        • 2013-03-04
        • 1970-01-01
        相关资源
        最近更新 更多