如何使用范围
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 2.2,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.3(当前的稳定版本)。
如何使用范围
这个条目都是关于作用域,有些先进的相关话题服务容器。如果你曾经得到一个错误提到“作用域”在创建服务时,或取决于需要创建一个服务请求
为你服务,那么这个条目。
理解范围
服务的范围控制多久的实例使用一个服务容器。DependencyInjection组件提供了两种通用的范围:
容器
(默认):使用相同的实例从这个容器每次请求它。原型
:每次创建一个新实例请求服务。
FrameworkBundle还定义了第三个范围:请求
。这个范围的请求,这意味着创建一个新的实例为每个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现在是当前请求
服务)。这是微妙的,但没别的可能会引发重大问题,这就是为什么这是不允许的。这就是原因为什么作用域存在,以及他们如何会导致一些问题。继续阅读,找出共同的解决方案。
请注意
服务当然可以依靠服务从一个更广泛的范围内没有任何问题。
设置范围的定义
服务的范围中设置服务的定义:
1 2 3 4 5
# src / Acme / HelloBundle /资源/ config / services.yml服务:greeting_card_manager:类:Acme \ HelloBundle \ \ GreetingCardManager邮件范围:请求
1 2 3 4
< !- - - - - -- - - - - -src/Acme/HelloBundle/Resources/config/services.xml -->< /span><服务><服务id=“greeting_card_manager”类=“Acme \ HelloBundle \ \ GreetingCardManager邮件”范围=“请求”/ >< /服务>
1 2 3 4 5 6 7
/ / src / Acme / HelloBundle /资源/ config / services.php使用ob娱乐下载\组件\DependencyInjection\定义;美元容器- >setDefinition (“greeting_card_manager”,新定义(“Acme \ HelloBundle \ \ GreetingCardManager邮件”))- >setScope (“请求”);
如果你不指定范围,它默认容器
大部分时间,这是你想要的东西。除非你的服务依赖于另一个服务范围的狭窄范围(最常见的是,请求
服务),你可能不需要设置范围。
使用服务从一个狭窄的范围
如果你的服务取决于一个作用域的服务,最好的解决方案是把它放在相同的范围(或一个窄)。通常,这意味着把你的新服务请求
范围。
但这并不总是可能的(例如,必须在树枝延伸容器
范围的树枝环境需要依赖)。在这些情况下,您应该通过整个集装箱到你的服务和检索您的依赖从容器每次你需要确保你有正确的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/ / src / Acme / HelloBundle /邮件/ Mailer.php名称空间Acme\HelloBundle\邮件;使用ob娱乐下载\组件\DependencyInjection\ContainerInterface;类梅勒{受保护的美元容器;公共函数__construct(ContainerInterface美元容器){美元这- >容器=美元容器;}公共函数sendEmail(){美元请求=美元这- >容器- >get (“请求”);/ /……使用请求做某事吗}}
谨慎
注意不要将请求存储在一个对象的属性为未来服务的调用,因为它会导致同样的问题描述的第一部分(除了Symfony不能检测到你错了)。ob娱乐下载
这个类的服务配置会看起来像这样:
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”#范围:容器可以省略,因为它是默认的
1 2 3 4 5 6 7 8 9 10 11
< !- - - - - -- - - - - -src/Acme/HelloBundle/Resources/config/services.xml -->< /span><参数>< !- - - - - -- - - - - -。。。- - ><参数关键=“my_mailer.class”>Acme \ HelloBundle \邮件\梅勒< /参数>< /参数><服务><服务id=“my_mailer”类=“% my_mailer.class %”><论点类型=“服务”id=“service_container”/ >< /服务>< /服务>
1 2 3 4 5 6 7 8 9 10 11
/ / src / Acme / HelloBundle /资源/ config / services.php使用ob娱乐下载\组件\DependencyInjection\定义;使用ob娱乐下载\组件\DependencyInjection\参考;/ /……美元容器- >setParameter (“my_mailer.class”,“Acme \ HelloBundle \邮件\梅勒”);美元容器- >setDefinition (“my_mailer”,新定义(“% my_mailer.class %”,数组(新引用(“service_container”))));
请注意
将整个容器注入服务通常不是一个好主意(只有注入您所需要的)。在某些罕见的情况下,它是必要的,当你有一个服务的容器
需要一个服务的范围请求
范围。
如果你定义一个控制器作为服务就可以得到请求
对象没有注入容器,它作为参数传入你的动作方法。看到控制器获取详细信息。