如何使用范围
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 2.1,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.3(当前的稳定版本)。
如何使用范围
这个条目都是关于作用域,有些先进的相关话题服务容器。如果你曾经得到一个错误提到“作用域”在创建服务时,还是需要创建一个服务,它取决于请求的服务,那么这个条目是给你的。
理解范围
服务的范围控制多久的实例使用一个服务容器。依赖注入组件提供了两种通用的范围:
- “容器”(默认):使用相同的实例每次请求从这个容器。
- “原型”:每次创建一个新实例请求服务。
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”))));
请注意
将整个容器注入服务通常不是一个好主意(只有注入您所需要的)。在某些罕见的情况下,它是必要的,当你有一个服务的容器
需要一个服务的范围请求
范围。
如果你定义一个控制器作为服务就可以得到请求
对象没有注入容器,它作为参数传入你的动作方法。看到控制器获取详细信息。