当前位置: 首页 > 知识库问答 >
问题:

在Symfony2中,为什么注入服务容器而不是单个服务是个坏主意?

龙德义
2023-03-14

我找不到这个问题的答案。。。

如果我注入服务容器,如:

// config.yml
my_listener:
   class: MyListener
   arguments: [@service_container]

my_service:
   class: MyService

// MyListener.php
class MyListener
{
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function myFunction()
    {
        $my_service = $this->container->get('my_service');
        $my_service->doSomething();
    }
}

那么它的工作原理就和我的一样好:

// config.yml
my_listener:
   class: MyListener
   arguments: [@my_service]

my_service:
   class: MyService

// MyListener.php    
class MyListener
{
    protected $my_service;

    public function __construct(MyService $my_service)
    {
        $this->my_service = $my_service;
    }

    public function myFunction()
    {
        $this->my_service->doSomething();
    }
}

那么,我为什么不直接注入服务容器,然后从类中获取服务呢?

共有3个答案

邵劲
2023-03-14

这不是一个好主意,因为你让你的类依赖于DI。当有一天你决定退出你的课,把它用在一个完全不同的项目上时,会发生什么?现在我不是在谈论Symfony,甚至不是PHP,我是在笼统地谈论。因此,在这种情况下,您必须确保新项目使用相同类型的DI机制,支持相同的方法,否则会出现异常。如果项目根本不使用DI,或者使用一些很酷的新DI实现,会发生什么?你必须检查你的整个代码库,并改变一些东西来支持新的DI。在大型项目中,这可能是有问题的和昂贵的,尤其是当你拉不止一个类的时候。

最好使你的类尽可能独立。这意味着把DI排除在你通常的代码之外,就像第三个人决定什么去哪里,指出东西应该去哪里,但不去那里自己做。我是这样理解的。

虽然,正如tomazahlin所说,我同意在Symfony项目中,在极少数情况下,它有助于防止循环依赖。这是唯一一个我会使用它的例子,我会确保这是唯一的选择。

秦滨海
2023-03-14

除其他人解释的所有缺点外(无法控制使用的服务、运行时编译、缺少依赖项等)

有一个主要原因,它打破了使用DIC依赖替换的主要优势。

如果服务是在库中定义的,您将无法用满足您需求的本地依赖替换它。

只有这个原因足够强,不能注入整个DIC。你只是打破了替换依赖项的整个想法,因为它们是硬编码的!在役;)

顺便说一句,不要忘记在服务构造函数中尽可能多地要求接口,而不是特定的类,这也是很好的替换。

编辑:依赖项替换示例

某些供应商中的服务定义:

<service id='vendor_service' class="My\VendorBundle\SomeClass" />
    <argument type="service" id="vendor_dependency" />
</service>

应用程序中的替换:

<service id='vendor_service' class="My\VendorBundle\SomeClass" />
     <argument type="service" id="app_dependency" />
</service>

这允许您用定制的逻辑替换供应商逻辑,但不要忘记实现所需的类接口。使用硬编码依赖项,您无法在一个地方替换依赖项。

您还可以覆盖vendor\u dependency服务,但这将在所有位置取代它,而不仅仅是在vendor\u服务中。

安轶
2023-03-14

我列出了您选择注射服务的原因:

>

  • 您的类只依赖于它所需要的服务,而不依赖于服务容器。这意味着该服务可以在不使用Symfony服务容器的环境中使用。例如,您可以将您的服务转换为一个库,可以在Laravel、Phalcon等中使用—您的类不知道依赖项是如何注入的。

    通过在配置级别定义依赖项,您可以使用配置转储程序了解哪些服务正在使用哪些其他服务。例如,通过注入@mailer,就很容易从注入mailer的服务容器中计算出来。另一方面,如果您使用$container-

    编译容器时,而不是在运行时,将通知您缺少依赖项。例如,假设您定义了一个服务,并将其注入到侦听器中。几个月后,您不小心删除了服务配置。如果要注入服务,清除缓存后会立即通知您。如果注入服务容器,则只有当侦听器因容器无法获取服务而失败时,才会发现错误。当然,如果你有彻底的集成测试,你可以拿起这个,但是...你有彻底的集成测试,不是吗?;)

    如果您注入了错误的服务,您将很快知道。例如,如果您有:

    public function __construct(MyService $my_service)
    {
       $this->my_service = $my_service;
    }
    

    但是您已经将监听器定义为:

    my_listener:
        class: Whatever
        arguments: [@my_other_service]
    

    当侦听器接收到MyOtherService时,PHP将抛出一个错误,告诉您它接收的类是错误的。如果您正在执行$container-

    如果您使用的是IDE,那么键入提示会增加一大堆额外的帮助。如果您使用$service=$容器-

    public function __construct(MyService $my_service)
    {
       $this->my_service = $my_service;
    }
    

    然后您的IDE知道$this-

    你的代码更容易阅读。所有依赖项都在类的顶部定义。如果它们分散在类中,则使用$container-

    代码更容易进行单元测试。如果要注入服务容器,则必须模拟服务容器,并将模拟配置为返回相关服务的模拟。通过直接注入服务,您只需模拟服务并注入它们——您跳过了整整一层复杂性。

    不要被“它允许懒惰加载”的谬论所愚弄。您可以在配置级别配置延迟加载,只需将服务标记为延迟: true

    就个人而言,注入服务容器是最好的解决方案的唯一时间是在我试图将安全上下文注入到条令侦听器时。这会引发循环引用异常,因为用户存储在数据库中。结果是,理论和安全上下文在编译时相互依赖。通过注入服务容器,我能够绕过循环依赖。然而,这可能是一种代码味道,有一些方法可以解决(例如,通过使用事件调度器),但我承认增加的复杂性可能会超过好处。

  •  类似资料:
    • 本文向大家介绍容器在微服务中的用途是什么?相关面试题,主要包含被问及容器在微服务中的用途是什么?时的应答技巧和注意事项,需要的朋友参考一下 容器是管理基于微服务的程序以便单独开发和部署它们的好方法。你可以将微服务封装在容器镜像及其依赖项中,然后可以用它来滚动开发按需实例的微服务而无需任何额外的工作。

    • 在我前面的问题Bluemix中,使用服务器推送应用程序。xml与整个Liberty服务器相比,性能有差异吗?我认为可以用多个Websphere Liberty Profile Server 8.5将单个Websphere Application Server 8替换为多个应用程序,其中每个Websphere Liberty Profile Server将承载一个应用程序。 我对这份声明感到担忧 已

    • 我有一个关于邮件服务器的基本问题。通常,任何通用服务器(不一定是邮件服务器)都会处理所有类型的相关请求,即与客户机的双向交互(比如向客户机发送和接收消息),但如果是邮件服务器,有两个不同的服务器——一个用于发送邮件,称为遵循SMTP协议的传出服务器,另一个用于接收邮件,称为遵循POP3/IMAP协议的传入服务器。为什么。因此,这两个协议不能在一个协议中容纳,以处理双向消息流。另外,在一般业务中,这

    • 问题内容: 我已经使用Flask一段时间了,我真的很喜欢这个框架。我无法理解的一件事是,在几乎所有其他地方,他们都在谈论将会话存储在服务器上,并将会话ID存储在客户端上,然后标识会话。但是,使用烧瓶后,我觉得没有必要这样做。以加密方式将会话另存为客户端cookie符合我的目的,而且似乎也很安全。唯一的原因是我无法为以下项加密会话密钥: 会显示为 在客户端上保存的Cookie中。但是,由于它仍处于加

    • 当我执行时,我的服务按预期列出,但当我从web或通过功能测试访问我的包时,我得到: 未捕获的PHP异常Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException:“您请求了一个不存在的服务”xx。处理程序”在xx/app/bootstrap。php。缓存行2031{“异常”:“[对象](Symfony\Compo