阿江 2017-10-12 16:25:59 90次浏览 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
*/

(全文完)

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