如何去装饰服务
当既有定义被覆写时,老的服务定义会消失:
|
$container->register('foo', 'FooService');
// this is going to replace the old definition with the new one
// 这会用新定义取代老定义
// old definition is lost 旧定义消失了
$container->register('foo', 'CustomFooService'); |
多数情况下,这确实是你想要的。但有时,你可能需要改装旧服务而不是取而代之。在上例中,旧服务应该保持“能被新服务引用”的状态。下面的配置文件把foo替换成了一个新服务,但是新服务拥有一个旧foo的引用,叫bar.inner
:
|
bar:
public: false
class: stdClass
decorates: foo
arguments: ["@bar.inner"] |
|
<service id="bar" class="stdClass" decorates="foo" public="false">
<argument type="service" id="bar.inner" />
</service> |
|
use Symfony\Component\DependencyInjection\Reference;
$container->register('bar', 'stdClass')
->addArgument(new Reference('bar.inner'))
->setPublic(false)
->setDecoratedService('foo'); |
此处发生的是:setDecoratedService()
方法告诉容器,bar
服务要取代foo服务。根据命名约定(convention),老的foo
服务将被重命名为bar.inner
,所以你可以将它注入到你的新服务中。
这个生成的inner id是基于装修者服务的(此处为bar
),不是被装修的服务(此处为foo
)。这允许多个装修者出现在同一服务上(它们需要生成不同的inner ids)。
多数情况下,装修者应该声明为私有(private),因为你不需要从容器中取用它。被装饰的foo
服务(装饰之后该服务使用bar
假名)的可见性,则仍然保持着原始的未装修之前的状态。
如果需要,你可以改变inner服务的名字:
|
bar:
class: stdClass
public: false
decorates: foo
decoration_inner_name: bar.wooz
arguments: ["@bar.wooz"] |
|
<service id="bar" class="stdClass" decorates="foo" decoration-inner-name="bar.wooz" public="false">
<argument type="service" id="bar.wooz" />
</service> |
|
use Symfony\Component\DependencyInjection\Reference;
$container->register('bar', 'stdClass')
->addArgument(new Reference('bar.wooz'))
->setPublic(false)
->setDecoratedService('foo', 'bar.wooz'); |
如果你需要把一个以上的装修者(decorator)用在一个服务上,你可以控制它们的顺序,通过配置装修优先级(priority of decoration),它可以是任何整数(高优先级的decorators会排在前面)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
foo:
class: Foo
bar:
class: Bar
public: false
decorates: foo
decoration_priority: 5
arguments: ['@bar.inner']
baz:
class: Baz
public: false
decorates: foo
decoration_priority: 1
arguments: ['@baz.inner'] |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="Http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="foo" class="Foo" />
<service id="bar" class="Bar" decorates="foo" decoration-priority="5" public="false">
<argument type="service" id="bar.inner" />
</service>
<service id="baz" class="Baz" decorates="foo" decoration-priority="1" public="false">
<argument type="service" id="baz.inner" />
</service>
</services>
</container> |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
use Symfony\Component\DependencyInjection\Reference;
$container->register('foo', 'Foo')
$container->register('bar', 'Bar')
->addArgument(new Reference('bar.inner'))
->setPublic(false)
->setDecoratedService('foo', null, 5);
$container->register('baz', 'Baz')
->addArgument(new Reference('baz.inner'))
->setPublic(false)
->setDecoratedService('foo', null, 1); |
(在容器中)生成的代码会是下面这样:
|
$this->services['foo'] = new Baz(new Bar(new Foo()))); |