gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-10-31 22:52:34 24 4
gpt4 key购买 nike

我想通过使某些类可观察来促进我的 PHP 代码中的松散耦合。 Symfony EventDispatcher component看起来很有希望,SPL 也是如此 SplObserver/SplSubject对类。

做到这一点的最佳方法是什么? 我可以看到几种不同的可能性:

(1) 在每个可观察类中注入(inject)一个 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: Increasing application size means a congruent increase in complexity.



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

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

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

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

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

继续类比,随着您的个性随着时间的推移慢慢改变(并且会),这种缺乏沟通会阻止您的伴侣了解如何最好地与您互动。最终,所有违背 promise 和未接来电的事情都变得一团糟,这种关系不再有效。它坏了。

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

进入事件管理

这就是事件管理的全部意义所在。目标是为我们的对象提供一种相互通信的方式,这种方式不会对它们需要与之通信的对象进行硬编码的关系。与大多数编程问题一样,没有一种单一的、特定的、“正确”的方法可以做到这一点。您的问题特别提到了实现此目的的两种可用方法,因此我将解决这些问题。如果您想了解其他一些选项,@ircmaxell 最近发布了 a nice survey blog post about making PHP apps "pluggable" .

观察员

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

当这种情况发生时,您已经开始尝试实现松散耦合,但是您创建了一个不同类型的问题:手动附加所有观察者和主题。例如,如果您的应用程序中的每个类都是 Logger 的主题,那么您已经为自己创造了很多工作。观察者对象。另外, 恕我直言 此方法有时会通过将可能更准确地描述为主题的实际依赖项的内容移出主题构造函数的方法签名来模糊您的 API。

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

调解员

管理事件的更健壮的方法是插入一个集中层来处理将事件分派(dispatch)给适当的监听器。这是什么 Mediatorwiki模式(和 Symfony 事件调度程序)确实如此。

Mediator 的重点在于它是系统中每个事件的集中中转站,因此它需要在整个应用程序范围内(或被调解的部分,无论如何)都可以访问。注意,这个 意味着您应该将其视为全局变量并使用全局关键字随意访问 Mediator,或者将其包装在某种邪恶的单例对象或静态属性/方法中。这种滥用会导致@liquorvicar 在第一个答案中提出的问题。但是,我强烈不同意该答案的评估:

"Having an eventDispatcher that's everywhere in your app and does almost everything can make your code harder to test/understand/maintain etc (it can approach a God object)"



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

回答

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

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

关于php - 使用 Symfony 的 EventDispatcher 组件的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9776364/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com