在Symfony2中,为什么注入服务容器而不是单独的服务是一个坏主意? [英] In Symfony2, why is it a bad idea to inject the service container, rather than individual services?

查看:156
本文介绍了在Symfony2中,为什么注入服务容器而不是单独的服务是一个坏主意?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找不到答案...

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

If I inject the service container, like:

// 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();
    }
}

那么它的工作原理如下:

then it works just as well as if I do:

// 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();
    }
}

那么为什么我不应该只是注入服务容器,并从我的课堂里获得这些服务?

So why shouldn't I just inject the service container, and get the services from that inside my class?

推荐答案

我希望注册服务的原因列表:

My list of reasons why you should prefer injecting services:


  1. 您的课程仅依赖于所需的服务,而不依赖于服务容器。这意味着该服务可以在不使用Symfony服务容器的环境中使用。例如,您可以将您的服务转换为可用于Laravel,Phalcon等的库 - 您的类不知道依赖关系如何注入。

  1. Your class is dependent only on the services it needs, not the service container. This means the service can be used in an environment which is not using the Symfony service container. For example, you can turn your service into a library that can be used in Laravel, Phalcon, etc - your class has no idea how the dependencies are being injected.

通过在配置级别定义依赖关系,您可以使用配置转储程序来了解哪些服务正在使用哪些其他服务。例如,通过注入 @mailer ,那么从邮件程序注入的服务容器中解决这个问题就很容易了。另一方面,如果您执行 $ container-> get('mailer'),那么几乎只有找出邮件程序被使用的唯一方法是做一个 find

By defining dependencies at the configuration level, you can use the configuration dumper to know which services are using which other services. For example, by injecting @mailer, then it's quite easy to work out from the service container where the mailer has been injected. On the other hand, if you do $container->get('mailer'), then pretty much the only way to find out where the mailer is being used is to do a find.

相反,容器被编译时会收到关于缺少依赖关系的通知在运行时。例如,假设您定义了一个将您注入到监听器中的服务。几个月后,您不小心删除了服务配置。如果您正在注册该服务,则在清除缓存后,系统会立即收到通知。如果您注入服务容器,则只有在侦听器发生故障时才会发现错误,因为容器无法获取该服务。当然你可以选择这个,如果你有彻底的集成测试,但是你有彻底的集成测试,不是吗? ;)

You'll be notified about missing dependencies when the container is compiled, instead of at runtime. For example, imagine you have defined a service, which you are injecting into a listener. A few months later, you accidentally delete the service configuration. If you are injecting the service, you'll be notified as soon as you clear the cache. If you inject the service container, you'll only discover the error when the listener fails because of the container cannot get the service. Sure, you could pick this up if you have thorough integration testing, but ... you have got thorough integration testing, haven't you? ;)

如果您正在注入错误的服务,您会更快知道。例如,如果你有:

You'll know sooner if you are injecting the wrong service. For example, if you have:

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

但是您已将侦听器定义为:

But you've defined the listener as:

my_listener:
    class: Whatever
    arguments: [@my_other_service]

当监听器收到 MyOtherService 时,PHP会抛出错误,告诉您收到错误的类。如果你正在做 $ container-> get('my_service'),你假定容器返回正确的类,可能需要很长时间出来,它的'不。

When the listener receives MyOtherService, then PHP will throw an error, telling you that it's receiving the wrong class. If you're doing $container->get('my_service') you are assuming that the container is returning the right class, and it can take a long time to figure out that its' not.

如果您使用的是IDE,那么输入hinting会增加一大堆额外的帮助。如果你使用 $ service = $ container-> get('service'); 那么你的IDE不知道什么 $ service 是。如果你注入

If you're using an IDE, then type hinting adds a whole load of extra help. If you're using $service = $container->get('service'); then your IDE has no idea what $service is. If you inject with

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

那么你的IDE知道 $ this-> my_service 是一个 MyService 的实例,可以帮助方法名称,参数,文档等。

then your IDE knows that $this->my_service is an instance of MyService, and can offer help with method names, parameters, documentation, etc.

您的代码更容易阅读。所有的依赖项都定义在课堂顶部。如果他们被分散在整个课堂里,而 $ container-> get('service')则可能难以确定。

Your code is easier to read. All your dependencies are defined right there at the top of the class. If they are scattered throughout the class with $container->get('service') then it can be a lot harder to figure out.

您的代码更容易进行单元测试。如果您正在注入服务容器,则必须模拟服务容器,并配置模拟器以返回相关服务的模拟。通过直接注射服务,您只需嘲笑服务并注入服务即可。您可以跳过一整套复杂的问题。

Your code is easier to unit test. If you're injecting the service container, you've got to mock the service container, and configure the mock to return mocks of the relevant services. By injecting the services directly, you just mock the services and inject them - you skip a whole layer of complication.

不要被愚弄允许懒惰加载谬误。您可以在配置级别配置延迟加载 只需将服务标记为 lazy:true

Don't be fooled by the "it allows lazy loading" fallacy. You can configure lazy loading at configuration level, just by marking the service as lazy: true.

个人而言,注入服务容器的唯一时间是我尝试注入安全性时最好的解决方案语境成为一个教义听众。这是抛出一个循环引用异常,因为用户被存储在数据库中。结果是在编译时,学说和安全背景依赖于彼此。通过注入服务容器,我能够绕过循环依赖。然而,这可能是一个代码气味,并且有其它方法(例如,通过使用事件调度程序),但我承认增加的并发症可以超过好处。

Personally, the only time injecting the service container was the best possible solution was when I was trying to inject the security context into a doctrine listener. This was throwing a circular reference exception, because the users were stored in the database. The result was that doctrine and the security context were dependent on each other at compile time. By injecting the service container, I was able to get round the circular dependency. However, this can be a code smell, and there are ways round it (for example, by using the event dispatcher), but I admit the added complication can outweigh the benefits.

这篇关于在Symfony2中,为什么注入服务容器而不是单独的服务是一个坏主意?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆