Symfony服务仅在方法调用后启动

时间:2016-10-02 00:30:13

标签: symfony dependency-injection

我注意到,只有在调用该服务中的方法时,才会启动Symfony服务(执行构造函数)。如果您的服务只有构造函数而没有方法,那么这很重要。

例如:

class MyService {

    public function __construct($someOtherService) {

        $someOtherService->setFoo("bar");

    }
}

// And of course put this service in services.yml

app.my_service:
    class: AppBundle\...\MyService
    arguments: [ app.some_other_service ]

在这种情况下,不调用构造函数和setFoo(“bar”)。为什么是这样?是否有可能以某种方式强制服务启动,而无需在此服务上调用(虚拟)方法?

我还尝试为app.my_service添加“lazy:false”,但这没什么区别。

我正在使用Symfony 2.8。

3 个答案:

答案 0 :(得分:4)

如果从未使用过您的服务,那么它们永远不会被实例化。要强制实例化服务,您可以挂钩到任何适合您事件的事件侦听器,当您想要获得服务(即kernel.request)并将此服务作为依赖项传递给侦听器时。这将在容器生命周期内第一次触发事件时触发服务构造函数。

但我建议您查看架构。只使用构造函数服务是无意义的

此外,您可以在EvendDispatcher实例化时实例化服务(仅因为它取决于您的服务)而不会触发事件

听众样本:

class ServiceInstantiatorListener
{
  public function onRequest(KernelEvent $kernel)
  {
     return; //noop, just make sure it works
  }

  public function instantiate($service)
  {
     return $service; // noop again, just call to pass service container argument
  }
}

yaml config:

services:
  my_app.service_instantiator_listener:
    class: My\App\ServiceInstantiatorListener
    tags:
    - { 'name': 'kernel_events', 'event': 'kernel.request', 'method':'onRequest' }
    calls:
    - [instantiate, ["@my_app.weird_service_one"]]
    - [instantiate, ["@my_app.weird_service_two"]]

更进一步,您可以使用标记标记您的服务,并使用MyAppBundleExtension编译器通行证动态配置调用

http://symfony.com/doc/current/service_container/tags.html#create-a-compiler-pass

我希望有更好的方法来强制实例化服务(即一些容器内部事件),但目前我还没有遇到我需要的情况。

答案 1 :(得分:1)

您正在描述延迟加载服务的行为。检查lazy: true的配置并删除/禁用它。

Symfony docs, lazy loaded service:

  

当您尝试与服务进行交互时,实际的类将被实例化(例如,调用其中一种方法)。

答案 2 :(得分:1)

您并不需要在服务上调用虚拟方法来启动它。 您可以使用以下语句实例化服务对象:

<强> $这 - &GT;容器() - &GT;获得(&#39; app.my_service&#39);