如何直接在Symfony 4+上访问未注入的服务? [英] How to access not-injected services directly on Symfony 4+?

查看:93
本文介绍了如何直接在Symfony 4+上访问未注入的服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Symfony 2.8更新为Symfony 4,并且在服务注入方面遇到严重问题。

I'm trying to update Symfony 2.8 to Symfony 4 and I am having serious problems with the Services Injection.

我正在寻找使用服务的新方法在控制器内部,并具有自动接线功能:

I'm looking the new way to use Services inside Controllers, with auto-wiring:

use App\Service\AuxiliarService;
class DefaultController extends AbstractController
{
    public function index(AuxiliarService $service)
    {
        $var = $service->MyFunction();
        ....

这种方式很好用,但我不喜欢引用的显式方式 MyService 作为函数的参数。这样,我什至无需在 services.yaml

This way works fine, but I dislike the explicit way to refer MyService as a parameter of the function. This way I don't even need to register the Service in the services.yaml

中注册服务。可以使用任何方式Symfony 2.8中的服务:

Is any way to use Services as in Symfony 2.8:

class DefaultController extends Controller
    {
        public function index()
        {
            $var = $this->get('AuxiliarService')->MyFunction(); /*Doesn't need to be explicit indicate before*/
            ....

使用services.yaml

With the services.yaml

services:
    auxiliar_service:
        class:        AppBundle\Services\AuxiliarService
        arguments: 
            entityManager: "@doctrine.orm.entity_manager"
            container: "@service_container" #I need to call services inside the service

这样,我就无需在Controller函数中将Service表示为参数。在某些情况下,在一个Service内部,我需要根据数据调用10个以上的服务,因此请指出它们是函数中的一个参数,这很烦人。

This way I don't need to indicate the Service as a parameter in the function of the Controller. In some cases, inside a Service, I need to call more than 10 services depends on the data, so indicate them as a parameter in the function is annoying.

另一个疑问Symfony 4中的方法是如何在不将其作为参数或参数传递的情况下在另一个Service中调用服务。过去通过注入服务容器可以在服务内部调用服务成为可能。

Another doubt in Symfony 4, is how to call a Service inside another Service without pass it as an argument or parameter. It used to be possible by injecting the service container to be able to call a service inside a service:

$this->container->get('anotherService')

在Symfony 4中,我认为它更昂贵(

In Symfony 4, I think it is more expensive (in code) use Service because you have to explicitely indicate them when you are going to use them.

推荐答案

tldr;在代码中)使用Service,因为您必须在使用它们时明确指出它们。 ,您可以通过使用服务订阅者&定位器

在您的控制器中:

use App\Service\AuxiliarService;
class DefaultController extends AbstractController
{
    public function index(AuxiliarService $service)
    {
        $var = $service->MyFunction();
    }

    public static function getSubscribedServices()
    {
        return array_merge(parent::getSubscribedServices(), [
            // services you want to access through $this->get()
            'auxiliar_service' => AuxiliarService:class,
        ]);
    }
// rest of the implementation
}

如果您的服务需要实现类似的模式,因此需要实现 ServiceSubscriberInterface AbstractController

If your service needs to implement a similar pattern, you'll need to implement ServiceSubscriberInterface (AbstractController, that you are extending for your controller, already does that for you).

class AuxiliaryService implements ServiceSubscriberInterface
{
    private $container;

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

    protected function has(string $id): bool
    {
        return $this->container->has($id);
    }

    protected function get(string $id)
    {
        return $this->container->get($id);
    }

    public static function getSubscribedServices()
    {
        return [
            // array_merge is not necessary here, because we are not extending another class. 
            'logger' => LoggerInterface::class,
            'service2' => AnotherService::class,
            'service3' => AndMore::class
        ];
    }
}






话虽如此,如果您想继续这种方式,您很有可能做错了事

在Symfony 4+之前,您可以做 $ this-> get('service'),因为这些控制器都可以访问容器。 为此,将依赖关系容器传递给它是一种反模式,不应这样做

Before Symfony 4+ you could do $this->get('service') because these controllers all had access to the container. Passing the dependency container around for this it is an anti-pattern, and shouldn't be done.

如果不声明依赖项,则会隐藏。该类的用户不知道其用途,并且通过更改隐藏的依赖项之一的行为更容易破坏系统。

If you do not declare your dependencies, your dependencies are hidden. Users of the class do not know what it uses, and it's easier to break the system by changing the behaviour of one of the hidden dependencies.

此外,Symfony提供了自动-接线和一个已编译的容器;

Furthermore, with Symfony providing auto-wiring and a compiled container; dependency injection is both easier to implement and faster to execute.

在执行此操作时遇到问题可能会揭示更深层的代码问题,您应该执行一些操作努力划分班级职责。一个服务可能依赖于您甚至在运行时甚至都不知道的许多其他服务这一事实,这是一种很强烈的气味,即关注点没有很好地分开。

That you are having trouble with implementing this probably reveals deeper issues with your code in general, and you should do some work on segregating the responsibilities of your classes. The fact that one service may depend on that many other services which you can't even know until runtime it's a very strong smell that the concerns are not well separated.

尝试适应这些变化,它将长期有益于您的应用程序和您自己(即使现在带来一点痛苦)。

Try to adapt to the changes, it will do your application and yourself good in the long term (even if brings a small amount of pain right now).

这篇关于如何直接在Symfony 4+上访问未注入的服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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