Yii的依赖注入容器和服务定位器

前言

Yii提供这两个类来进行解耦,功能有多强大呢?yii中创建的对象几乎都是通过容器的方式创建的, 可以看一下 Yii::createObject() 方法,而 $app 本身就是一个服务定位器。由于具体的细节比较多,如果需要详细代码可以参考深入理解Yii2.0和看源码,这里只说一下大概的原理

依赖注入容器 Container

为了解决两个类的强耦合,通常我们的做法是通过 构造方法 或者 属性赋值 的方式将一个对象注入到另一个对象中。小项目其实也没什么问题,但是当项目大起来的时候,依赖关系复杂的时候,就会让这个流程变得复杂起来, 容器就很好的解决类这个问题,只需要将依赖关系注册到容器,获取对象的时候容器自动将完成各对象之间的依赖关系。容器这里用的是 构造方法 注入的方式。

下面举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
namespace app\models;
use yii\base\Object;
use yii\db\Connection;
use yii\di\Container;
interface UserFinderInterface
{
function findUser();
}
class UserFinder extends Object implements UserFinderInterface
{
public $db;
public function __construct(Connection $db, $config = [])
{
$this->db = $db;
parent::__construct($config);
}
public function findUser()
{
}
}
class UserLister extends Object
{
public $finder;
public function __construct(UserFinderInterface $finder, $config = [])
{
$this->finder = $finder;
parent::__construct($config);
}
}
/*
容器的方式创建
*/
$container = new Container;
$container->set('yii\db\Connection', [
'dsn' => '...',
]);
$container->set('app\models\UserFinderInterface', [
'class' => 'app\models\UserFinder',
]);
$container->set('userLister', 'app\models\UserLister');
$lister = $container->get('userLister');
// 和下面的相同
/*
正常流程的创建
*/
$db = new \yii\db\Connection(['dsn' => '...']);
$finder = new UserFinder($db);
$lister = new UserLister($finder);

原理

可以看着上面的例子理解一下,首先我们先将所有的依赖关系注册进去,然后获取对象的时候会通过反射拿取到该类构造方法中定义的所依赖的对象,然后会在所注册的依赖中找到这个依赖,之后就是层层的递归不断的解析新出现的依赖。

服务定位器 ServiceLocator

上面已经所说 $app 就是一个服务定位器,其实服务定位器就是一个注册树,将组件注册到了它的上面
看一个例子应该就很明白了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$locator = new \yii\di\ServiceLocator;
// 在配置文件配置的Components参数,其实就是下面要完成的
$locator->setComponents([
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:path/to/file.db',
],
'cache' => [
'class' => 'yii\caching\DbCache',
'db' => 'db',
],
]);
// 调用服务定位中注册的组件,组件的创建是通过容器进行创建的
$db = $locator->get('db'); // or $locator->db
$cache = $locator->get('cache'); // or $locator->cache

没看明白的看源码吧,比较好理解

echo-ding wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!