如何使用范围
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 2.3,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.3(当前的稳定版本)。
如何使用范围
这个条目都是关于作用域,有些先进的相关话题服务容器。如果你曾经得到一个错误提到“作用域”在创建服务时,或取决于需要创建一个服务请求
为你服务,那么这个条目。
理解范围
服务的范围控制多久的实例使用一个服务容器。DependencyInjection组件提供了两种通用的范围:
容器
(默认):使用相同的实例从这个容器每次请求它。原型
:每次创建一个新实例请求服务。
的ContainerAwareHttpKernel还定义了第三个范围:请求
。这个范围的请求,这意味着创建一个新的实例为每个subrequest和不可用在请求(例如在CLI)。
范围添加一个约束依赖关系的服务:服务不能依赖服务从一个狭窄的范围。例如,如果您创建一个通用的my_foo
服务,但试图注入请求
服务,您将收到一个ScopeWideningInjectionException当编译容器。读下面的侧边栏的更多细节。
范围和依赖关系
想象你已经配置了my_mailer
服务。你没有配置服务的范围,所以它默认容器
。换句话说,每次你问的容器my_mailer
服务,您拿回相同的对象。这通常是你想要你的服务是如何工作的。
想象,然而,你需要请求
服务在你的my_mailer
服务,也许因为你阅读当前请求的URL。所以,你把它作为构造函数参数。这提出了一个问题:有几个原因
- 当请求
my_mailer
的一个实例,my_mailer
(称为MailerA和创建)请求
服务(称为RequestA)被传递给它。生活是美好的! - 你现在在Symfony subrequest,这是一种奇特的方式ob娱乐下载说你叫,例如,
{{渲染(…)}}
树枝函数,执行另一个控制器。在内部,老请求
服务(RequestA)实际上是被一个新的请求实例(RequestB)。这发生在后台,这完全是正常的。 在你的嵌入式控制器,你再次询问
my_mailer
服务。因为你的服务容器
范围,相同的实例(MailerA)是重用。但问题是:MailerA实例仍然包含旧的RequestA对象,它是现在不正确的请求对象(RequestB现在是当前请求
服务)。这是微妙的,但没别的可能会引发重大问题,这就是为什么这是不允许的。这就是原因为什么作用域存在,以及他们如何会导致一些问题。继续阅读,找出共同的解决方案。
请注意
服务当然可以依靠服务从一个更广泛的范围内没有任何问题。
使用服务从一个狭窄的范围
如果你的服务有依赖作用域的服务(如请求
),你有三种方式处理:
- 使用setter注入如果依赖“同步”;这是推荐的方式,最好的解决方案
请求
实例是同步的请求
范围(见如何使用范围); - 把你的服务在同一范围依赖(或一个窄)。如果你依靠
请求
服务,这意味着把你的新服务请求
范围(见如何使用范围); - 整个容器传递给你的服务和检索你的依赖从容器每次你需要确保你有正确的实例——您的服务可以住在默认
容器
范围(见如何使用范围)。
下面几节详细讨论每个场景。
使用一个同步服务
2.3
在Symfony 2.3中引入了同步服务。ob娱乐下载
注入容器或设置您的服务范围较窄范围有缺点。(如为同步服务请求
使用setter注入),是最好的选择,因为它没有缺点,一切正常,没有任何特殊代码在您的服务或您的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
/ / src / AppBundle /邮件/ Mailer.php名称空间AppBundle\邮件;使用ob娱乐下载\组件\HttpFoundation\请求;类梅勒{受保护的美元请求;公共函数setRequest(请求美元请求= null){美元这- >请求=美元请求;}公共函数sendEmail(){如果(零= = =美元这- >请求){/ /抛出一个错误?}/ /……使用请求做某事吗}}
每当请求
范围是进入或离开,服务容器会自动调用setRequest ()
方法与当前请求
实例。
您可能已经注意到,setRequest ()
方法接受零
作为一个有效的值请求
论点。这是因为当离开请求
范围,请求
实例可以零
(例如主请求)。当然,你应该照顾这种可能性在你的代码。这也应该考虑当宣布你的服务:
1 2 3 4 5 6
# app / config / services.yml服务:greeting_card_manager:类:AppBundle \ \ GreetingCardManager邮件电话:- - - - - -[setRequest,(@ ?请求= '))
1 2 3 4 5 6 7 8 9 10
< !- - - - - -- - - - - -app/config/services.xml -->< /span><服务><服务id=“greeting_card_manager”类=“AppBundle \ \ GreetingCardManager邮件”><调用方法=“setRequest”><论点类型=“服务”id=“请求”on-invalid=“零”严格的=“假”/ >< /调用>< /服务>< /服务>
1 2 3 4 5 6 7 8 9 10 11
/ / app / config / services.php使用ob娱乐下载\组件\DependencyInjection\定义;使用ob娱乐下载\组件\DependencyInjection\ContainerInterface;美元定义=美元容器- >setDefinition (“greeting_card_manager”,新定义(“AppBundle \ \ GreetingCardManager邮件”))- >addMethodCall (“setRequest”,数组(新引用(“请求”,ContainerInterface::NULL_ON_INVALID_REFERENCE,假)));
提示
您可以声明自己的同步
服务很容易;的声明请求
服务供参考:
1 2 3 4 5
服务:要求:范围:请求合成:真正的同步:真正的
1 2 3
<服务><服务id=“请求”范围=“请求”合成=“真正的”同步=“真正的”/ >< /服务>
1 2 3 4 5 6 7
使用ob娱乐下载\组件\DependencyInjection\定义;使用ob娱乐下载\组件\DependencyInjection\ContainerInterface;美元定义=美元容器- >setDefinition (“请求”)- >setScope (“请求”)- >setSynthetic (真正的)- >setSynchronized (真正的);
谨慎
服务使用同步服务需要公众为了setter范围变化时调用。
改变了你的服务的范围
改变服务的范围应该在它的定义:
1 2 3 4 5 6
# app / config / services.yml服务:greeting_card_manager:类:AppBundle \ \ GreetingCardManager邮件范围:请求参数:(“@request”)
1 2 3 4 5 6 7 8
< !- - - - - -- - - - - -app/config/services.xml -->< /span><服务><服务id=“greeting_card_manager”类=“AppBundle \ \ GreetingCardManager邮件”范围=“请求”><论点类型=“服务”id=“请求”/ >< /服务>< /服务>
1 2 3 4 5 6 7 8 9 10
/ / app / config / services.php使用ob娱乐下载\组件\DependencyInjection\定义;美元定义=美元容器- >setDefinition (“greeting_card_manager”,新定义(“AppBundle \ \ GreetingCardManager邮件”,数组(新引用(“请求”))))- >setScope (“请求”);
通过容器作为一个依赖你的服务
设置一个窄的范围并不总是可能的(例如,必须在树枝延伸容器
范围的树枝环境需要依赖)。在这些情况下,您可以通过整个集装箱到你的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/ / src / AppBundle /邮件/ Mailer.php名称空间AppBundle\邮件;使用ob娱乐下载\组件\DependencyInjection\ContainerInterface;类梅勒{受保护的美元容器;公共函数__construct(ContainerInterface美元容器){美元这- >容器=美元容器;}公共函数sendEmail(){美元请求=美元这- >容器- >get (“请求”);/ /……使用请求做某事吗}}
谨慎
注意不要将请求存储在一个对象的属性为未来服务的调用,因为它会导致同样的问题描述的第一部分(除了Symfony不能检测到你错了)。ob娱乐下载
这个类的服务配置会看起来像这样:
1 2 3 4 5 6
# app / config / services.yml服务:my_mailer:类:AppBundle \邮件\梅勒参数:(“@service_container”)#范围:容器可以省略,因为它是默认的
1 2 3 4 5 6
< !- - - - - -- - - - - -app/config/services.xml -->< /span><服务><服务id=“my_mailer”类=“AppBundle \邮件\梅勒”><论点类型=“服务”id=“service_container”/ >< /服务>< /服务>
1 2 3 4 5 6 7 8
/ / app / config / services.php使用ob娱乐下载\组件\DependencyInjection\定义;使用ob娱乐下载\组件\DependencyInjection\参考;美元容器- >setDefinition (“my_mailer”,新定义(“AppBundle \邮件\梅勒”,数组(新引用(“service_container”))));
请注意
将整个容器注入服务通常不是一个好主意(只有注入您所需要的)。
提示
如果你定义一个控制器作为服务就可以得到请求
对象没有注入容器,它作为参数传入你的动作方法。看到控制器获取详细信息。