您的位置:首页 > 产品设计 > UI/UE

理解PHP依赖注入容器(dependency injection container)系列(四) Symfony服务容器:利用Builder创建服务

2016-09-25 10:55 1161 查看
上篇讲述了利用继承sfServiceContainer类,为容器提供简单易用的接口调用。接下来我们会讲到如何进一步利用sfServiceContainerBuilder 类描述服务和配置。

sfServiceContainerBuilder是继承sfServiceContainer类的(每一个容器类如sfServiceContainer类都实现了sfServiceContainerInterface接口),它使开发者可以通过一种简洁易用的方式来描述服务。

服务的描述是通过注册服务定义完成的。每个服务定义描述了一个服务:从使用构造函数传递参数的类,和一堆其他的配置属性(见下面的sfservicedefinition边栏)

再回到Zend_Mail这个例子,现在我们要把其中的硬编码去除掉,并利用builder类动态创建它

require_once 'PATH/TO/sf/lib/sfServiceContainerAutoloader.php';
sfServiceContainerAutoloader::register();

$sc = new sfServiceContainerBuilder();

$sc->
register('mail.transport', 'Zend_Mail_Transport_Smtp')->
addArgument('smtp.gmail.com')->
addArgument(array(
'auth'     => 'login',
'username' => '%mailer.username%',
'password' => '%mailer.password%',
'ssl'      => 'ssl',
'port'     => 465,
))->
setShared(false)
;

$sc->
register('mailer', '%mailer.class%')->
addMethodCall('setDefaultTransport', array(new sfServiceReference('mail.transport')))
;


通过register()方法我们完成了对服务的创建。只需要给出service name和class name,该方法返回sfServiceDefinition实例。

服务定义在内部是通过sfservicedefinition对像实现的。也可以手工创建,再直接利用容器的setservicedefinition()方法登记。

sfServiceDefinition对像实现了一个接口并且提供了几个能对服务进行配置的方法,在上面的例子中,我们使用了这几个方法:

addArgument():给服务的构造函数传递一个参数。

setShared():在当前容器中,该服务是否唯一(默认情况下为true)

addMethodCall():设置服务被创建后触发的委托事件。第一个参数是要委托调用的方法,第二个参数是向方法传递的参数数组

sfServiceDefinition 的相关方法:

setConstructor():设置创建服务时使用的静态方法,用来替换标准的new __construct方式(一般用在对像工厂)

setClass:设置服务类

setArguments(): 为构造函数设置多个参数(顺序很关键)

addArgument(): 为构造函数设置一个参数

setMethodCalls():设置服务被创建后触发的委托事件方法簇,按造顺序执行。

addMethodCall():设置服务被创建后触发的委托事件,允许多次添加同一个方法。

setFile(): 设置一个文件包含路径,该文件将在创建服务前被引用include(在服务没有实现自动加载文件时有用)

setShared():在当前容器中,该服务是否唯一(默认情况下为true)

setConfigurator():设置委托方法,在服务配置完成后调用。

现在引用一个服务是通过实例化sfServiceReference类来实现的(如:new sfServiceReference(‘mail.transport’) .)。这个特殊的类可以根据参数动态的创建服务。

在注册过程中,服务并没有真正被创建,仅仅是描述了如何获取并配置该服务。只有在真正使用服务时,服务才会被实例化。这就是说,你可以在任何顺序任何位置创建注册你的服务,而不用担心服务依赖的对像是否在它之前注册。这也意味着后面注册的服务如果名字相同,则可以覆盖前面的服务。在测试时,需要重写一些方法时这不失为一个好的办法。

sfServiceContainerBuilder类实现了标准sfServiceContainerInterface接口。来看一下接口定义:

interface sfServiceContainerInterface
{
public function setParameters(array $parameters);
public function addParameters(array $parameters);
public function getParameters();
public function getParameter($name);
public function setParameter($name, $value);
public function hasParameter($name);
public function setService($id, $service);
public function getService($id);
public function hasService($name);
}


我们使用容器可以不用改变代码:

$sc->addParameters(array(
'mailer.username' => 'foo',
'mailer.password' => 'bar',
'mailer.class'    => 'Zend_Mail',
));

$mailer = $sc->mailer;


sfServiceContainerBuilder 可以描述如何实例化、配置对像。上面的Zend_Mail例子已经展示了这一切,现在我们看另一个来源于Symfony的例子,这个例子用到了sfUser类:

$sc = new sfServiceContainerBuilder(array(
'storage.class'        => 'sfMySQLSessionStorage',
'storage.options'      => array('database' => 'session', 'db_table' => 'session'),
'user.class'           => 'sfUser',
'user.default_culture' => 'en',
));

$sc->register('dispatcher', 'sfEventDispatcher');

$sc->
register('storage', '%storage.class%')->
addArgument('%storage.options%')
;

$sc->
register('user', '%user.class%')->
addArgument(new sfServiceReference('dispatcher'))->
addArgument(new sfServiceReference('storage'))->
addArgument(array('default_culture' => '%user.default_culture%'))->
;

$user = $sc->user;


容器参数的存储对像是通过数组传递的时侯,如果我们要使用某个参数,就要用到占位符(addArgument(‘%storage.options%’))

下一篇将介绍如何用 XML or YAML文件描述服务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐