[Yii2笔记]056服务定位器(Service Locator) [ 技术分享 ]
说明
学习Yii Framework 2(易2框架)的过程是漫长的,也是充满乐趣的,以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现,提供了较完整的代码,供你参考。不妥之处,请多多指正!
原文网址:
http://www.yiiframework.com/doc-2.0/guide-concept-service-locator.html
本文主题:服务定位器(Service Locator)
服务定位器(service locator)是一个对象,它知道如何提供应用中需要的各种各样的服务(或组件)。在一个服务定位器中,每个组件仅存在一个实例,并被标识为唯一的ID,你可以使用ID从服务定位器中获取一个组件。
在Yii2中,一个服务定位器就是yii\di\ServiceLocator或其子类的实例。
在Yii中使用服务定位器最多的是应用对象(application object),可以通过\Yii::$app 来获取。它提供的服务称为应用组件(application components),例如request,response,urlManager组件。通过服务定位器提供的各项功能,你可以配置这些组件,甚至可以使用你自己的实现去替代它们。
除了应用对象,每个模块对象(module object)也都是一个服务定位器。
要使用一个服务定位器,第一步需要使用服务定位器去注册组件,组件可以使用yii\di\ServiceLocator::set()注册。以下代码示范了注册组件的不同方法:
use yii\di\ServiceLocator;
use yii\caching\FileCache;
$locator = new ServiceLocator;
//使用类名注册"cache"服务,此类名可用于创建一个新组件。
$locator->set('cache', 'yii\caching\ApcCache');
//使用配置数组注册"db"服务,此配置数组可用于创建一个新组件。
$locator->set('db', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
]);
//使用匿名函数注册"search"服务,匿名函数可以创建一个组件
$locator->set('search', function () {
return new app\components\SolrService;
});
//使用一个组件注册"pageCache"服务
$locator->set('pageCache', new FileCache);
一旦一个组件被创建了,你就可以使用它的ID来获取它,使用以下两种方法之一即可:
$cache=$locator->get('cache');
$cache=$locator->cache;
如上所示,yii\di\ServiceLocator允许你使用组件ID象获取属性一样获取一个组件。当你第一次获取一个组件时,yii\di\ServiceLocator将使用组件的注册信息去创建一个新实例,并将它返回;如果再次获取这个组件,服务定位器将直接返回一个实例。
你可以使用yii\di\ServiceLocator::has()检查组件ID是否已经被注册了,如果你使用无效的ID调用yii\di\ServiceLocator::get()方法,将抛出一个异常。
通常是使用配置来创建服务定位器,通过一个名为components的可写属性来设置。它允许你一次配置和注册多个组件。以下代码展示了一个配置数组,它用于配置一个服务定位器(例如:application),有db、cache、search组件。
return [
// ...
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=demo',
'username' => 'root',
'password' => '',
],
'cache' => 'yii\caching\ApcCache',
'search' => function () {
$solr = new app\components\SolrService('127.0.0.1');
// ... other initializations ...
return $solr;
},
],
];
上述代码中,search的配置可以有一个替代的方法,创建SolrService实例时,无需直接编写回调匿名函数,而是使用静态类去返回一个回调匿名函数,代码如下:
class SolrServiceBuilder
{
public static function build($ip)
{
return function () use ($ip) {
$solr = new app\components\SolrService($ip);
// ... other initializations ...
return $solr;
};
}
}
return [
// ...
'components' => [
// ...
'search' => SolrServiceBuilder::build('127.0.0.1'),
],
];
这个替代方法在你发布一个包含第三方库的Yii组件时更为有效,你可以象上面一样使用一个静态方法来代表创建第3方组件的复杂逻辑,你的组件的使用者只需调用静态方法去配置组件即可。
//-----------------------------------------------
Service Locator实例
//----------------------------------------------- //创建一个Service Locator实例 D:\phpwork\advanced\frontend\controllers\PostController.php
use yii\di\ServiceLocator;
class PostController extends CommonController {
public function actionLocator(){
//创建服务定位器(service locator),名为$locator
$locator = new \yii\di\ServiceLocator;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//使用类名称向服务定位器注册一个ID为foo1的服务,此服务使用'frontend\models\FooModel'类创建,无参数
$locator->set('foo1','frontend\models\FooModel');
//使用配置数组创建一个foo2服务,使用'frontend\models\FooModel'类创建服务,提供了一个参数'para1',其值为'value22'
$locator->set('foo2', [
'class'=>'frontend\models\FooModel',
'para1'=>'value22',
]);
//使用匿名函数创建foo3服务,并给匿名传入一个参数$param,此参数为一个数组
$param=['para1'=>'value333'];
$locator->set('foo3',function() use ($param){
return new FooModel($param);
});
//直接创建一个FooModel对象,并将这个对象定义为foo4服务
$locator->set('foo4', new FooModel(['para1'=>'value4']));
//使用FooModel的静态方法build()创建一个对象并将这个对象定义为foo5服务
$locator->set('foo5', FooModel::build(['para1'=>'value5']));
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//调用服务定位器$locator的foo1服务,并将获取到的对象赋值给$foo1
$foo1=$locator->foo1;
//调用foo2服务赋给$foo2
$foo2=$locator->foo2;
//调用foo3服务赋给$foo3
$foo3=$locator->foo3;
//调用foo4服务赋给$foo4
$foo4=$locator->foo4;
//调用foo5服务赋给$foo5
$foo5=$locator->foo5;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//打印各个服务对象的para1属性:
echo "<br>foo1->para1:".$foo1->para1;
echo "<br>foo2->para1:".$foo2->para1;
echo "<br>foo3->para1:".$foo3->para1;
echo "<br>foo4->para1:".$foo4->para1;
echo "<br>foo5->para1:".$foo5->para1;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//再次调用foo5服务,并赋值给$foo52
$foo52=$locator->foo5;
//使用$foo5修改属性para1的值
$foo5->para1="value51";
//$foo52->para1的值与$foo5->para1相同,说明para1是同个对象的同一个属性
echo "<br>-------------------";
echo "<br>foo5->para1:".$foo5->para1;
echo "<br>foo52->para1:".$foo52->para1;
$foo52->para1="value52";
echo "<br>-------------------";
echo "<br>foo5->para1:".$foo5->para1;
echo "<br>foo52->para1:".$foo52->para1;
echo "<br>-------------------";
$foo52->para2="value522";
echo "<br>foo52->para2:".$foo52->para2;
}
D:\phpwork\advanced\frontend\models\FooModel.php
<?php
namespace frontend\models;
use yii\base\Object;
class FooModel extends Object{
public $para1;
public $para2;
public function bar(){
echo "This is FooMoel's bar()";
}
public static function build($param){
//在匿名函数中调用参数使用use($param)
return function () use ($param) {
$solr = new FooModel($param);
return $solr;
};
}
}
测试结果:
http://localhost:8082/post/locator
/*
foo1->para1:
foo2->para1:value22
foo3->para1:value333
foo4->para1:value4
foo5->para1:value5
-------------------
foo5->para1:value51
foo52->para1:value51
-------------------
foo5->para1:value52
foo52->para1:value52
-------------------
foo52->para2:value522
*/
(全文完)
共 0 条回复
阿江
最后登录:2024-03-03
在线时长:186小时21分
- 粉丝94
- 金钱16816
- 威望160
- 积分20276