传统的思路是应用程序在用到一个类的时候,就会创建这个类的对象并且调用方法。如果这个方法里面需要一个bar的类,那么就需要
new一个bar的对象去进行调用。。。bar类中还需要调用bim的类,那么就还需要new一个bim的类去进行调用。
1
2
3
4
5
6
7
8 1<?php// 代码【1】classBim{ publicfunctiondoSomething(){ echo__METHOD__, '|';
2 }
3}classBar{ publicfunctiondoSomething(){ $bim = new Bim(); $bim->doSomething(); echo__METHOD__, '|';
4 }
5}classFoo{ publicfunctiondoSomething(){ $bar = new Bar(); $bar->doSomething(); echo__METHOD__;
6 }
7}$foo = new Foo();$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
8
使用依赖注入的思路是应用程序中用到foo类,foo类需要用bar类,bar类需要用到bim类。那么先创建bim类,在创建bar类,把bim类注入到bar中,然后创建foo类,将bar注入到foo中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1<?php// 代码【2】class Bim{ public function doSomething()
2 { echo __METHOD__, '|';
3 }
4}class Bar{ private $bim; public function __construct(Bim $bim)
5 { $this->bim = $bim;
6 } public function doSomething()
7 { $this->bim->doSomething(); echo __METHOD__, '|';
8 }
9}class Foo{ private $bar; public function __construct(Bar $bar)
10 { $this->bar = $bar;
11 } public function doSomething()
12 { $this->bar->doSomething(); echo __METHOD__;
13 }
14}$foo = new Foo(new Bar(new Bim()));$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
15
以上代码说的就是控制反转模式。依赖关系的控制反转到调用链的起点。这样就可以完全空值依赖关系,通过调整不同注入对象来控制程序的行为。
通过一个最简单的容器类来解释一下,这段代码来自 Twittee
1
2
3
4
5
6
7 1<?phpclass Container{ private $s = array(); function __set($k, $c)
2 { $this->s[$k] = $c;
3 } function __get($k)
4 { return $this->s[$k]($this);
5 }
6}
7
这段代码使用了魔术方法,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。
1
2
3
4
5 1<?php$c = new Container();$c->bim = function () { return new Bim();
2};$c->bar = function ($c) { return new Bar($c->bim);
3};$c->foo = function ($c) { return new Foo($c->bar);
4};// 从容器中取得Foo$foo = $c->foo;$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
5
这段代码使用了匿名函数
再来一段简单的代码演示一下,容器代码来自simple di container
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1<?phpclass IoC{ protected static $registry = []; public static function bind($name, Callable $resolver)
2 { static::$registry[$name] = $resolver;
3 } public static function make($name)
4 { if (isset(static::$registry[$name])) { $resolver = static::$registry[$name]; return $resolver();
5 } throw new Exception('Alias does not exist in the IoC registry.');
6 }
7}
8
9IoC::bind('bim', function () { return new Bim();
10});
11IoC::bind('bar', function () { return new Bar(IoC::make('bim'));
12});
13IoC::bind('foo', function () { return new Foo(IoC::make('bar'));
14});// 从容器中取得Foo$foo = IoC::make('foo');$foo->doSomething(); // Bim::doSomething|Bar::doSomething|Foo::doSomething
15
这段代码使用了后期静态绑定
依赖注入容器 (dependency injection container) 高级功能
真实的dependency injection container会提供更多的特性,如
-
自动绑定(Autowiring)或 自动解析(Automatic Resolution)
-
注释解析器(Annotations)
-
延迟注入(Lazy injection)
不过说实话 这些东西 没写过。。要写过才知道