如何使用Scopes

编辑本页

警告:您正在浏览的文档欧宝官网下载appob娱乐下载Symfony 2.0,现已不再维护。

本页的更新版本用于Syob娱乐下载mfony 6.2(当前稳定版本)。

如何使用Scopes

这篇文章都是关于作用域的,这是与服务容器.如果您曾经在创建服务时遇到提到“作用域”的错误,或者需要创建依赖于“请求”服务的服务,那么这篇文章就是为您准备的。

理解范围

服务的作用域控制容器使用服务实例的时间。依赖注入组件提供了两个通用作用域:

  • ' container '(默认值):每次你从这个容器请求它时,都会使用相同的实例。
  • ' prototype ':每次请求服务都会创建一个新实例。

FrameworkBundle还定义了第三个作用域:' request '。此作用域与请求绑定,这意味着为每个子请求创建一个新实例,并且在请求之外不可用(例如在CLI中)。

作用域为服务的依赖关系添加了约束:服务不能依赖于更窄作用域内的服务。例如,如果你创建了一个通用的' my_foo '服务,但是尝试注入' request '组件,你会收到一个ScopeWideningInjectionException编译容器时。阅读下面的边栏了解更多详细信息。

假设您已经配置了一个' my_mailer '服务。您还没有配置服务的作用域,因此它默认为' container '。换句话说,每次向容器请求' my_mailer '服务时,都会得到相同的对象。这通常是您希望服务工作的方式。

但是,想象一下,您需要' my_mailer '服务中的' request '服务,可能是因为您正在读取当前请求的URL。你把它作为构造函数参数添加。让我们来看看为什么这会带来一个问题:

  • 当请求' my_mailer '时,' my_mailer '的一个实例(让我们调用它MailerA)和“请求”服务(让我们称它为RequestA)传递给它。生活是美好的!
  • 现在您已经在Symfony中发出了子请求,这是一种华丽的说法,例ob娱乐下载如,您已经调用了“{% render…”' Twig函数,它执行另一个控制器。在内部,旧的“请求”服务(RequestA)实际上被一个新的请求实例(RequestB).这是在后台发生的,完全正常。
  • 在嵌入式控制器中,再次请求' my_mailer '服务。由于您的服务在' container '范围内,因此相同的实例(MailerA)只是重复使用。但问题是:MailerA实例仍然包含旧的RequestA对象,也就是现在正确的请求对象(RequestB现在是当前的“请求”服务)。这是微妙的,但不匹配可能会导致重大问题,这就是为什么它是不允许的。

    这就是原因为什么范围是存在的,以及它们是如何引起问题的。请继续阅读,找出常见的解决方案。

请注意

服务当然可以依赖于更广泛范围内的服务,而不会出现任何问题。

在定义中设置范围

服务的作用域在服务的定义中设置:

  • YAML
  • XML
  • PHP
1 2 3 4 5
# src / Acme / HelloBundle /资源/ config / services.yml服务:greeting_card_manager:类:Acme \ HelloBundle \ \ GreetingCardManager邮件范围:请求

如果你没有指定作用域,它默认为' container ',这是你大多数时候想要的。除非您的服务依赖于另一个范围较窄的服务(最常见的是“请求”服务),否则您可能不需要设置范围。

在更窄的范围内使用服务

如果您的服务依赖于有作用域的服务,那么最好的解决方案是将其放在相同的作用域中(或更窄的作用域中)。通常,这意味着将您的新服务放在“请求”范围内。

但这并不总是可能的(例如,一个树枝扩展必须在“容器”范围内,因为树枝环境需要它作为一个依赖项)。在这些情况下,你应该将整个容器传递到你的服务中,并在每次需要时从容器中检索你的依赖项,以确保你有正确的实例:

12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20
/ / src / Acme / HelloBundle /邮件/ Mailer.php名称空间AcmeHelloBundle邮件使用ob娱乐下载组件DependencyInjectionContainerInterface梅勒受保护的容器公共函数__construct(ContainerInterface容器->容器=容器;}公共函数sendEmail()请求->容器->get (“请求”);/ /……使用这里的请求做一些事情}}

谨慎

注意不要将请求存储在对象的属性中,以便将来调用服务,因为这将导致与第一节中描述的相同的问题(除非Symfony无法检测到您的错误)。ob娱乐下载

这个类的服务配置看起来像这样:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6 7 8 9 10
# src / Acme / HelloBundle /资源/ config / services.yml参数:#……my_mailer.class:Acme \ HelloBundle \邮件\梅勒服务:my_mailer:类:“% my_mailer.class %”参数:-“@service_container”# scope:容器可以省略,因为它是默认的

请注意

将整个容器注入到服务中通常不是一个好主意(只注入您需要的部分)。在极少数情况下,当您有服务时,这是必要的容器对象中需要服务的范围请求范围。

如果将控制器定义为服务,则可以获得请求对象,而不注入容器,通过将其作为操作方法的参数传入。看到控制器获取详细信息。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。