如何使用scope

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 2.7,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

如何使用scope

本文都是关于作用域的,这是与服务容器.如果您曾经在创建服务时遇到过提到“作用域”的错误,那么本文就是为您准备的。

请注意

如果你想注射请求服务,简单的解决方案是注入request_stack方法来访问当前请求getCurrentRequest ()方法(参见如何从服务容器中检索请求).本文的其余部分将以理论和更高级的方式讨论作用域。如果你要处理的是请求服务,只需注入request_stack

理解范围

服务的作用域控制容器使用服务实例的时间。DependencyInjection组件提供了两个泛型作用域:

容器(默认值):
每次从容器中请求时,都会使用相同的实例。
原型
每次请求服务时都会创建一个新实例。

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

示例:客户端范围

除了请求service(它有一个简单的解决方案,请参阅上面的说明),默认的Symfony容器中没有服务属于除欧宝娱乐app下载地址容器而且原型.但是为了本文的目的,假设存在另一个范围客户端还有服务client_configuration那是属于它的。这不是一个常见的情况,但想法是你可以进入和退出多个客户端范围,每个范围都有自己的范围client_configuration服务。

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

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

但是,想象一下,您需要client_configuration在贵公司服务my_mailer服务,可能是因为您正在从中读取一些详细信息,例如“发件人”地址应该是什么。将其作为构造函数参数添加。这是一个问题的几个原因:

  • 当请求my_mailer,一个实例my_mailer(称为MailerA在这里)是创建的client_configuration服务(调用ConfigurationA此处)传递给它。生活是美好的!
  • 您的应用程序现在需要对另一个客户端执行一些操作,并且您已经将应用程序设计为通过输入newclient_configuration范围和设置一个新的client_configuration服务装入容器。调用这个ConfigurationB
  • 在应用程序的某个地方,您再次要求my_mailer服务。既然你是在容器范围,相同的实例(MailerA)只是重复使用。但问题是:MailerA实例仍然包含旧的ConfigurationA对象,也就是现在要拥有的正确配置对象(ConfigurationB现在是电流client_configuration服务)。这是微妙的,但不匹配可能会导致重大问题,这就是为什么它是不允许的。

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

请注意

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

从更窄的范围使用服务

范围问题有两种解决方案:

  • A)将您的服务置于与依赖项相同的范围(或更窄的范围)。如果你依赖于client_configuration服务,这意味着将新服务放在客户端范围(见如何使用scope);
  • B)将整个容器传递给你的服务,并在每次需要时从容器中检索你的依赖项,以确保你有正确的实例——你的服务可以存在于默认的实例中容器范围(见如何使用scope).

每个场景将在以下部分中详细介绍。

请注意

在Symfony 欧宝娱乐app下载地址2.7之前,有另一种基于同步服务。但是,从Symfony 2.7开始,这类服务就已经弃用了。欧宝娱乐app下载地址

A)改变服务范围

更改服务的范围应该在其定义中完成。这个例子假设梅勒类有一个__construct ()函数的第一个参数为ClientConfiguration对象:

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / services.yml服务:my_mailer:类:AppBundle \邮件\梅勒范围:客户端参数:(“@client_configuration”)

B)将容器作为服务的依赖项传递

将作用域设置为较窄的范围并不总是可能的(例如,分支扩展必须位于容器因为Twig环境需要它作为依赖项)。在这些情况下,你可以将整个容器传递到你的服务中:

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

谨慎

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

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

  • YAML
  • XML
  • PHP
1 2 3 4 5 6
# app / config / services.yml服务:my_mailer:类:AppBundle \邮件\梅勒参数:(“@service_container”)# scope:容器可以省略,因为它是默认的

请注意

将整个容器注入到服务中通常不是一个好主意(只注入您需要的部分)。

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