symfony - 依赖注入(inject)或服务定位器-Symfony

标签 symfony dependency-injection service-locator

我已经开始阅读Symfony2代码,研究了一些小类(如Pimple),经过几个小时的检查,得出了一个奇怪的主意。最好的开始是解释我如何理解几个术语,因此:

依赖性
工作需要其他东西,例如“汽车”中的“发动机”

容器
可以存储许多其他对象的对象或类,例如“引擎”,“齿轮箱”甚至“汽车”

依赖项注入(inject)
每个依赖项都注入(inject)到对象的过程,因此,如果我需要“汽车”,我知道我必须注入(inject)“引擎”,“齿轮箱”和许多其他东西。重要的是,“汽车”不会创建“引擎”,而是将“引擎”放置在“汽车”内部

服务定位器
对象在其中请求另一个对象的过程,例如,在汽车中插入了我们的容器,并且当汽车需要启动时,需要从容器“engine”开始,因此容器将其返回“engine”

当我学习Symphony代码时,它们从依赖关系注入(inject)开始,但是一段时间后,我意识到创建Controller时,会注入(inject)整个容器,然后您可以使用$ this-> get('serviceName')来获取它,因此看起来更像是服务定位器,根据几篇文章,它是反模式的。

母 pig 怎么样DI和SL之间的线是否太小而有时会断开?还是我误会了什么?如果我使用DI,是否需要将每个服务插入 Controller ,所以我从外面知道我使用了什么?还是在某些情况下 Controller 可以成为容器?

最佳答案

您对DI的理解非常好。是的,Symfony Controller 确实实现了ContainerAwareInterface,并且如您所说,它具有服务定位器角色。但是服务定位器不是反模式。每种模式都有其正确和不正确的用法。

此外,Symfony不会以任何方式强制您使用它的Controller。您的 Controller can be a service。 hell ,它甚至可以是一个功能!

这是将 Controller 实现为服务定位符的原因之一:性能

让我们抛开汽车类比,专注于在99%的项目中会遇到的真实案例:您需要CRUD作为资源。假设您正在构建 Todo 应用,并且需要一个RESTfulish Controller 来处理任务资源的CRUD操作。

您至少需要有一种读取所有任务的方法和添加新任务的方法,为此,您需要执行两个操作:索引(通常也称为 list ),以及存储(通常称为 create) )。

用伪代码在Symfony中常见的流程是这样的:

indexAction -> getDoctrine -> getTaskRepository -> getAllTasks

storeAction -> getFormFactory -> createForm -> bindRequestDataToForm -> getDoctrine -> saveData

如果Controller是服务定位器

索引 Action

当执行 index 操作时,只有将从容器中解析的服务才是 ManagerRegistry (在这种情况下为 Doctrine 服务)。然后,我们将要求它提供给我们任务库,然后我们将对其进行操作。

商店行动

当执行存储操作时,我们将做更多的工作:让容器给我们 FormFactory ,对其进行一些操作,然后要求它给我们教义并对其进行一些操作。

总结:执行索引操作时,服务容器仅必须构建一个服务,而执行更新时,则必须构建两个服务。

如果Controller是常规服务

让我们看看 Controller 需要什么。从上面的部分中,我们看到它需要 FormFactory 教义

现在,当您只想调用索引操作以从数据存储中读取所有任务时,您的 Controller 将必须通过容器实例化。在实例化容器之前,容器需要实例化其依赖项:FormFactory和Doctrine。然后实例化 Controller ,同时将这两个注入(inject)其中。

因此,您正在调用索引操作,该操作根本不需要 FormFactory ,但是您仍然有创建它的开销,因为在该请求中根本不会调用该操作是必需的。

懒惰服务

为了减少这种开销,有一种叫做lazy service的东西。它实际上是通过将服务的代理注入(inject)到 Controller 中来工作的。因此,就 Controller 而言,它获得了 FormFactory 。它不知道不是真正的 FormFactory,而是一个假对象,当您在其上调用某些方法时,该对象将把调用委托(delegate)给真正的 FormFactory 代码。

包起来

Controller 不必是服务定位器,但可以是。使它成为服务定位器可以提高性能,并易于引导,但隐藏了依赖项。此外,由于您需要模拟依赖项容器,因此测试起来有些困难。您是否要使 Controller 的服务,功能或服务定位器成为您的选择,Symfony不会强制您使用任何这些方式。

以我的经验,只要您不在其中编写业务逻辑,而是将所有工作委托(delegate)给从容器中获取的服务,那么扩展默认的 Symfony Controller 并将 Controller 作为服务定位符就等于
。这样,您几乎不可能在 Controller 代码中出现错误(因为方法通常由2-3行代码组成)并且可以在不进行测试的情况下逃脱。

关于symfony - 依赖注入(inject)或服务定位器-Symfony,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26304755/

相关文章:

php - Symfony 为用户提供多种角色

symfony - 异常处理 app/logs/dev.log

java - 由于 java.lang.NullPointerException 导致的 BeanInstantiationException

architecture - 我应该如何在我的应用程序中构建日志记录?

dependency-injection - 为什么 MVC4 使用服务定位器反模式?

asp.net-mvc - MVC3、Ninject、MvcSiteMapProvider - 如何将依赖项注入(inject)到重写方法

php - 在 Docker 环境中运行 Symfony 时的文件夹权限

symfony2 如何创建自己的自定义 yml 文件以在全局共享?

java - 是否可以使用在同一个 @Configuration 类中定义的 @Resource 实例?

javascript - 循环依赖,当 ovveriding ExceptionHandler