PHP/Symfony:为什么 TwigExtension 注入的服务实例与 Controller 不同?

PHP/Symfony: Why does a TwigExtension get a different service instance injected than a Controller?

版本:

背景

怎么回事?

我有一个 shared 服务,它被注入并在我的 Controller 中使用。

还有一个 TwigExtension,它注入了相同的服务并期望完全相同的服务实例

  • Why does the TwigExtension rely on the service to being the same instance anyway?
    • The service contains specific data which the TwigExtension processes. Basically the service seems to be currently used as kind of a request specific global data container or data collector.
  • At this point you might argue that this sounds like a questionable practice and ask why I am actually doing something like this.
    • I am dealing with an existing application, with existing functionality depending on the described behaviour.
    • I'd be happy to get the application working in a first step, and change suspicious workarounds in a second one.

预期行为:

实际行为:

旧版本中的行为(Symfony 2.x):

我尝试了什么:

我的问题:

我不知道为什么你没有相同的共享服务实例。根据 Symfony 文档,如果它在同一个请求中,您应该拥有相同的服务实例。

In the service container, all services are shared by default. This means that each time you retrieve the service, you'll get the same instance.

如果您找不到解决此问题的方法,您有两种存储数据的方法。 Session 用于简单格式,数据库用于更复杂和长期存储。

原来是为同一个class定义了两个服务。

在 services.yml 中手动定义了一项服务,服务 ID 为 'service'。在 Symfony 2.x.

时代,手动定义服务是定义服务的唯一方法

然后 autowire 出现了,基本上用它们的 class 名称的 id 定义了服务。我们能够使用 "bin/console debug:container" 验证这确实是问题所在。这是升级到 Symfony 3.4+ 并启用自动装配的结果。

除了创建服务,autowire 还允许您通过针对 class 名称的类型提示来注入服务。如果在容器中找到匹配的服务 ID,则注入该服务。因此,在这种情况下,twig 扩展可能更改为使用类型提示,而控制器使用 $container->get 导致注入两种不同的服务。或者反之亦然。

一个解决方法是使用别名:

# services.yml
MyServiceClassName: service

别名基本上会抑制第二个服务的自动生成。

一种 "better" 方法(或至少更推荐的方法)是停止使用 $container->get 并只在需要的地方注入服务。然后,您将完全删除 'service' 定义。

最后一点,如果服务本身需要任何缩放器构造函数参数(字符串或整数),那么自动装配过程将失败并显示错误消息。这些错误最初可能非常令人困惑,因为您已经定义了一个工作服务,但由于服务 ID 不同,自动装配只是向前推进并尝试创建一个新服务。