我已经开始阅读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/