php依赖注入容器

最近在学习使用Laravel,对Laravel中容器的概念很感兴趣,所以写一篇博客来学习一下。

什么是依赖注入?

把有依赖关系的类放到容器中,解析出这些类的实例,就是依赖注入。目的是实现类的解耦

实例

Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。
采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。

一般情况下的

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
class A
{
public function __construct(B $b)
{
$this->b = $b;
}

public function message()
{
$this->b->say();
//code
echo '卑微小A';
}
}

class B
{
public function __construct(C $c)
{
$this->c = $c;
}

public function say()
{
$this->c->taunt();
echo '哈哈,你离不开我吧'.PHP_EOL;
}
}

class C
{
public function taunt()
{
echo '辣鸡,没有我你们行不';
}

}

$c = new C();
$b = new B($c);
$a = new A($b);
$a->message();

从上面的示例来看,有一个明显的问题,就是如果一个顶层的类A依赖太多的底层类B,C时,代码会非常的多,而且还会一不小心搞错依赖顺序,不够优雅。

这个时候,我们来思考下有没有什么办法能自动解决这些依赖,来优雅的书写这些代码?这个方法就是我们今天的主题,依赖注入(DI)

废话不多说,先来个示例代码

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
//创建一个容器
//代码来自 https://github.com/fabpot-graveyard/twittee
class Container {
private $s=array();
function __set($k, $c) { $this->s[$k]=$c; }
function __get($k) { return $this->s[$k]($this); }
}

//使用容器来请求方法。
$container = new Container();
$container->c = function () {
return new C();
};
$container->b = function ($class) {
return new B($class->c);
};

$container->a = function ($class) {
return new A($class->b);
};
$container->a->message();
//print:
//辣鸡,没有我你们行不
//哈哈,你离不开我吧
//卑微小A[Finished in 0.0s]

上面是最简单的容器实现代码以及使用。从上面的代码来看,确实比之前优雅了许多,在同一个进程中,所有的方法都只需要在容器中实例化一次,之后,在任何的地方,都可以直接调用,而不用再关心依赖。

到这里,一个简单的 DI 容器就实现好了。但是,我们还是希望它能够更加的智能。比如:

  • 自动绑定(AutoWiring) 或 自动解析(Automatic Resolution)
  • 注释解析器(Annotations)
  • 延迟注入(Lazy injection)

我们下期再来一起探讨。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

请我喝杯咖啡吧~