使用 Symfony 的 EventDispatcher 组件的正确方法是什么?

2024-04-19

我想通过使某些类可观察来促进 PHP 代码中的松散耦合。交响乐的事件分发器组件 https://github.com/symfony/EventDispatcher看起来很有希望,SPL 也是如此Spl观察者 http://php.net/splobserver/主题 http://php.net/splsubject一对类。

最好的方法是什么?我可以看到几种不同的可能性:

(1) 将 EventDispatcher 实例注入到每个可观察类中(跟踪全局 EventDispatcher 实例):

class Foo
{
    public function __construct($dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }

    public function bar()
    {
        $this->dispatcher->dispatch(...);
    }
}

(2) 让 observable 类扩展 EventDispatcher 类:

class Foo extends EventDispatcher
{
    public function bar()
    {
        $this->dispatch(...);
    }
}

(3) 使用SplObserver/SplSubject——简单,但不如EventDispatcher组件灵活


免责声明:这个答案与 Symfony EventDispatcher 无关,但与您的问题有关。如果您只想得到答案,您可以跳过(某种程度上)学术讨论并跳到最后。

讨论

FACT:应用程序大小的增加意味着复杂性的相应增加。

随着应用程序范围的扩大,您会发现自己添加了越来越多的类来实现必需的功能。突然间,想起来并不那么容易了Foo当对象需要执行某些特定操作时Bar对象被创建。此外,当您的对象开始为彼此提供补充功能时,在不以非常紧密耦合的对象结束的情况下维持必要的关系变得越来越困难。

我们需要一种方法让对象能够进行通信,而无需对显式引用进行硬编码,而当某些内容发生变化时我们会忘记更改这些引用。那么,我们如何管理快速增长的对象图的节点之间的这种相互关联的功能呢?

如果你想让它持久,你就必须说话

让我们稍微绕一下,考虑一个浪漫的比喻......

任何关系要想长久,都需要持续的沟通。当然,你和你的伴侣可以在周六晚上聚在一起进行阴暗的勾搭,而在本周剩下的时间里不互相交谈。然而,这种类型的沟通通常会导致脆弱的关系,双方都不了解对方实际上需要什么才能在这种关系中正常运作。

继续类比,随着时间的推移,你的性格会慢慢发生变化(而且它会发生变化),缺乏沟通会阻止你的伴侣理解如何最好地与你互动。最终,所有违背的承诺和未接的电话都达到了顶峰,关系就不再有效了。它坏了。

您的应用程序以同样的方式工作。代码应该足够成熟,可以说:“嘿宝贝,我可能会改变,但如果我改变了,我保证我会永远让你知道我发生了什么。”不幸的是,随着复杂性的增加,传统的直线应用程序设计使得在类之间没有紧密耦合的情况下很难维持这种通信。

进入活动管理

这就是事件管理的意义所在。目标是为我们的对象提供一种相互通信的方式,而不会硬编码与需要通信的对象的关系。与大多数编程问题一样,没有单一的、具体的、“正确”的方法来做到这一点。您的问题特别提到了实现此目的的两种可用方法,因此我将解决这些方法。如果您想了解其他一些选项,@ircmaxell 最近发布了一篇关于使 PHP 应用程序“可插拔”的不错的调查博客文章 http://blog.ircmaxell.com/2012/03/handling-plugins-in-php.html.

Observer

在实践中,您会发现很少有适用于观察者模式的实际 PHP 应用程序。这是因为,如果您希望代码非常动态,那么很快您就可以将观察者附加到各处的主题对象。

当这种情况发生时,你就得到了你开始试图实现的松散耦合,但你却产生了不同类型的问题:手动附加所有观察者和主题。例如,如果应用程序中的每个类都是某个类的主题,那么您就为自己创建了大量工作。Logger观察者对象。还,IMHO此方法有时会将可能更准确地描述为主题的实际依赖项的内容从主题构造函数的方法签名中移出,从而使您的 API 变得模糊。

如果我们使用集中式调度程序在事件发生时通知感兴趣的对象,我们的应用程序将会更加灵活,尽管观察者模式对于一次性或简单的情况可能是理想的选择。

Mediator

A more robust way to manage events is by inserting a centralized layer to handle dispatching events to the appropriate listeners. This is what the Mediatorwiki http://en.wikipedia.org/wiki/Mediator_pattern pattern (and the Symfony event dispatcher) does.

中介者的要点在于,它是系统中每个事件的集中中转站,因此需要在整个应用程序范围(或中介部分)中访问它。仔细注意一下,这个does not意味着您应该将其视为全局变量并使用全局关键字随意访问中介器或将其包装在某种邪恶的单例对象或静态属性/方法中。这种滥用将导致@liquorvicar在第一个答案中提出的问题。然而,我强烈不同意该答案的评估:

“在您的应用程序中拥有一个无处不在且几乎可以完成所有操作的 eventDispatcher 会使您的代码更难测试/理解/维护等(它可以接近上帝对象)”

仅当您滥用 Mediator 时才会出现这种情况;它应该发送事件通知而不是其他任何内容。我会警告您不要像您在选项中建议的那样扩展它(2)因为这个原因你的问题。如果使用得当,中介对象是非常可测试的。没有什么比模拟构造函数中指定的依赖对象的行为更简单的了。这就是单元测试的意义所在。

Answer

因此,如果您在应用程序中需要非线性事件管理,我强烈建议选择(1)从你的问题来看。只要你不滥用它,这是完全可以接受的。掩饰 Symfony 实现,它似乎支持任何可作为侦听器调用的 PHP。就我个人而言,我更喜欢一个允许延迟实例化基于类的侦听器的系统,以获得更高效和面向对象的范例,但实现细节取决于您。

责任链模式与中介者密切相关,是实现类似结果的另一种有效方法。如果您有兴趣,我建议您使用之前发布的 @ircmaxell 博客文章的链接。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Symfony 的 EventDispatcher 组件的正确方法是什么? 的相关文章

  • 为什么 LinkedIn v2 Share API 在任何 v2/shares 端点上给出权限不足的错误?

    当我调用任何 v2 LinkedIn 共享 API 端点时 例如https api linkedin com v2 socialActions https api linkedin com v2 socialActions share UR
  • Monolog,如何将 PHP 数组记录到控制台?

    我正在使用浏览器处理程序将消息记录到 JS 控制台 require once vendor autoload php use Monolog Logger use Monolog Handler BrowserConsoleHandler
  • Godaddy 托管上的 CakePHP 控制台

    我一直在努力让我的 CakePHP 网站在 Godaddy 网格托管 帐户上运行 我的蛋糕应用程序设置是从帐户的子目录托管的 并且可以通过子域访问 我必须调整我的 htaccess 文件才能使其正常工作 现在我需要让 CakePHP 控制台
  • 有没有办法在不使用 foreach 或其他函数的情况下在 PHP 中内爆关联数组的键和值?

    我有一个像这样的关联数组 myarray array a gt 1 b gt 2 c gt 3 我想显示数组键和值 如下所示 a is 1 b is 2 c is 3 我不想使用 print r 或 var dump 来执行此操作 我也不想
  • PHP:STR 替换为链接

    我有这个 PHP 聊天框 如果我在聊天框中键入链接 它不会将其显示为链接 我如何使用 STR 替换来执行此操作 它应该响应诸如 http http com nl www www 之类的内容 我的其他 STR 替换行如下所示 bericht
  • 如何在 Laravel 中 session_write_close() ?

    Running session write close before sleep 在 Laravel 中似乎不起作用 因为会话仍然被其他请求阻止 直到当前连接完成 我试图sleep 在 Laravel 中 不会阻止其他请求 发现 sessi
  • PHP:在多维数组中查找相同的键并合并结果

    我有一个多维数组 如下所示 array 0 gt array WS gt array id gt 2 name gt hello 1 gt array SS gt array id gt 1 name gt hello2 2 gt arra
  • HTTP_REFERER 返回 NULL,$_SERVER 中不存在密钥

    使用以来第一次 SERVER HTTP REFERER 它给了我NULL因此 当我做var dump SERVER the HTTP REFERER密钥不存在 我还尝试使用不同的浏览器和不同的网站访问网站 但没有结果 该网站在基于 Linu
  • 从父类调用重写的虚拟方法

    假设您正在编写原始 C Object类并且您想要以下功能 object1 object2将比较引用 除非该运算符被覆盖 object1 object2将始终返回对象实际值的倒数object1 object2 所以 举例来说 如果我有一个Bu
  • 在 Laravel 中按数据透视表 create_at 排序

    在我的数据库中 我有以下表格 courses id 名称 创建时间 更新时间 students id 名称 创建时间 更新时间 课程 学生 id course id student id created at updated at 我正在尝
  • Lumen 微框架 => php artisan key:generate

    我正在尝试 PHP 微框架 Lumen 来自 Laravel 我的第一步就是调查 env example文件并复制一份以供我使用 env文件 就像 Laravel 中一样 有一个变量 APP KEY 现在我尝试了简单的命令php artis
  • 如何使用额外标记输出 wp_list_categories

    我目前正在使用下面的脚本在无序列表中输出我的所有 WordPress 类别 如何获得带有额外标记的输出 ul ul 例如 ul li Category 1 rsaquo li li Category 2 rsaquo li ul 代替 ul
  • Mandrill 验证错误

    很高兴能在 StackOverflow 上提出我的第一个问题 多年来我一直依靠它自学了很多东西 我的问题是这样的 尝试通过 Mandrill 的 API 发送邮件时出现以下错误 status error code 1 name Valida
  • PHP OOP 静态属性语法错误 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 为什么不
  • PHP URL 验证

    我知道有无数的线程问这个问题 但我一直无法找到一个可以帮助我解决这个问题的线程 我基本上试图解析大约 10 000 000 个 URL 的列表 确保它们根据以下标准有效 然后获取根域 URL 此列表包含您能想象到的几乎所有内容 包括类似的内
  • 打印表数据mysql php

    我在尝试打印表格的一些数据时遇到问题 我是 php mysql 的新手 但我认为我的代码是正确的 这里是 h1 Lista de usu rios h1
  • 通过 SOAP 的 Gmt php 或 UTC C# 等效项

    is C DateTime UtcNow和 PHPdate c 是等价的 我怀疑 因为当我肥皂时 我得到了 C
  • Magento 设置脚本中的 ALTER TABLE 不使用 SQL

    乔纳森 戴 https stackoverflow com users 336905 jonathan day says 更新不应采用以下形式 SQL命令 我没遇到过 任何 DDL 或 DML 语句不能 通过 Magento 的配置执行 结
  • 在 Windows 上查看 PHP 文件夹

    我正在编写一个简单的 PHP 脚本来监视文件夹及其子文件夹的任何更改 新文件 修改 删除 然后执行操作 我将使用 Windows 上的命令行运行此脚本php f script php 我一直在寻找一种在 Windows 上观看具有 PHP
  • 准备好的语句需要 0 个参数,给定 1 个参数..,使用 php 手册示例 [重复]

    这个问题在这里已经有答案了 我直接从 php 手册示例中获取了这个 它几乎与我需要的相同 但我仍然收到此错误 有人可以告诉我我错过了什么吗 stmt link gt prepare SELECT obitBody Photo FROM tn

随机推荐