阿江 2017-10-12 16:25:59 2695次浏览 0条回复 0 0 0

说明

学习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
*/

(全文完)

    没有找到数据。
您需要登录后才可以回复。登录 | 立即注册