这里接着上一篇 php依赖注入,直接贴出完整代码如下:
<?phpclass C{ ???public function doSomething() ???{ ???????echo __METHOD__, ‘我是C类|‘; ???}}class B{ ???private $c; ???public function __construct(C $c) ???{ ???????$this->c = $c; ???} ???public function doSomething() ???{ ???????$this->c->doSomething(); ???????echo __METHOD__, ‘我是B类|‘; ???}}class A{ ???private $b; ???public function __construct(B $b) ???{ ???????$this->b = $b; ???} ???public function doSomething() ???{ ???????$this->b->doSomething(); ???????echo __METHOD__, ‘我是A类|‘;; ???}}
//这段代码使用了魔术方法,在给不可访问属性赋值时,__set() 会被调用。读取不可访问属性的值时,__get() 会被调用。class Container{ ???private $s = array(); ???function __set($k, $c) ???{ ???????$this->s[$k] = $c; ???} ???function __get($k) ???{ ???????return $this->s[$k]($this); ???}}
$class = new Container();$class->c = function () { ???return new C();};$class->b = function ($class) { ???return new B($class->c);};$class->a = function ($class) { ???return new A($class->b);};// 从容器中取得A$model = $class->a;$model->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|
再来一段简单的代码演示一下,容器代码来自simple di container,完整如下:
<?phpclass C{ ???public function doSomething() ???{ ???????echo __METHOD__, ‘我是C类|‘; ???}}class B{ ???private $c; ???public function __construct(C $c) ???{ ???????$this->c = $c; ???} ???public function doSomething() ???{ ???????$this->c->doSomething(); ???????echo __METHOD__, ‘我是B类|‘; ???}}class A{ ???private $b; ???public function __construct(B $b) ???{ ???????$this->b = $b; ???} ???public function doSomething() ???{ ???????$this->b->doSomething(); ???????echo __METHOD__, ‘我是A类|‘;; ???}}class IoC{ ???protected static $registry = []; ???public static function bind($name, Callable $resolver) ???{ ???????static::$registry[$name] = $resolver; ???} ???public static function make($name) ???{ ???????if (isset(static::$registry[$name])) { ???????????$resolver = static::$registry[$name]; ???????????return $resolver(); ???????} ???????throw new Exception(‘Alias does not exist in the IoC registry.‘); ???}}IoC::bind(‘c‘, function () { ???return new C();});IoC::bind(‘b‘, function () { ???return new B(IoC::make(‘c‘));});IoC::bind(‘a‘, function () { ???return new A(IoC::make(‘b‘));});// 从容器中取得A$foo = IoC::make(‘a‘);$foo->doSomething(); // C::doSomething我是C类|B::doSomething我是B类|A::doSomething我是A类|
这段代码使用了后期静态绑定
依赖注入容器的高级功能
真实的dependency injection container会提供更多的特性,如
自动绑定(Autowiring)或 自动解析(Automatic Resolution)
注释解析器(Annotations)
延迟注入(Lazy injection)
下面的代码在Twittee的基础上,实现了Autowiring。
<?phpclass C{ ???public function doSomething() ???{ ???????echo __METHOD__, ‘我是周伯通C|‘; ???}}class B{ ???private $c; ???public function __construct(C $c) ???{ ???????$this->c = $c; ???} ???public function doSomething() ???{ ???????$this->c->doSomething(); ???????echo __METHOD__, ‘我是周伯通B|‘; ???}}class A{ ???private $b; ???public function __construct(B $b) ???{ ???????$this->b = $b; ???} ???public function doSomething() ???{ ???????$this->b->doSomething(); ???????echo __METHOD__, ‘我是周伯通A|‘;; ???}}class Container{ ???private $s = array(); ???public function __set($k, $c) ???{ ???????$this->s[$k] = $c; ???} ???public function __get($k) ???{ ???????// return $this->s[$k]($this); ???????return $this->build($this->s[$k]); ???} ???/** ????* 自动绑定(Autowiring)自动解析(Automatic Resolution) ????* ????* @param string $className ????* @return object ????* @throws Exception ????*/ ???public function build($className) ???{ ???????// 如果是匿名函数(Anonymous functions),也叫闭包函数(closures) ???????if ($className instanceof Closure) { ???????????// 执行闭包函数,并将结果 ???????????return $className($this); ???????} ???????/** @var ReflectionClass $reflector */ ???????$reflector = new ReflectionClass($className); ???????// 检查类是否可实例化, 排除抽象类abstract和对象接口interface ???????if (!$reflector->isInstantiable()) { ???????????throw new Exception("Can‘t instantiate this."); ???????} ???????/** @var ReflectionMethod $constructor 获取类的构造函数 */ ???????$constructor = $reflector->getConstructor(); ???????// 若无构造函数,直接实例化并返回 ???????if (is_null($constructor)) { ???????????return new $className; ???????} ???????// 取构造函数参数,通过 ReflectionParameter 数组返回参数列表 ???????$parameters = $constructor->getParameters(); ???????// 递归解析构造函数的参数 ???????$dependencies = $this->getDependencies($parameters); ???????// 创建一个类的新实例,给出的参数将传递到类的构造函数。 ???????return $reflector->newInstanceArgs($dependencies); ???} ???/** ????* @param array $parameters ????* @return array ????* @throws Exception ????*/ ???public function getDependencies($parameters) ???{ ???????$dependencies = []; ???????/** @var ReflectionParameter $parameter */ ???????foreach ($parameters as $parameter) { ???????????/** @var ReflectionClass $dependency */ ???????????$dependency = $parameter->getClass(); ???????????if (is_null($dependency)) { ???????????????// 是变量,有默认值则设置默认值 ???????????????$dependencies[] = $this->resolveNonClass($parameter); ???????????} else { ???????????????// 是一个类,递归解析 ???????????????$dependencies[] = $this->build($dependency->name); ???????????} ???????} ???????return $dependencies; ???} ???/** ????* @param ReflectionParameter $parameter ????* @return mixed ????* @throws Exception ????*/ ???public function resolveNonClass($parameter) ???{ ???????// 有默认值则返回默认值 ???????if ($parameter->isDefaultValueAvailable()) { ???????????return $parameter->getDefaultValue(); ???????} ???????throw new Exception(‘I have no idea what to do here.‘); ???}}// ----$class = new Container();$class->b = ‘B‘;$class->a = function ($class) { ???return new A($class->b);};// 从容器中取得A$model = $class->a;$model->doSomething(); $di = new Container();$di->php7 = ‘A‘;/** @var A $php7 */$foo = $di->php7;var_dump($foo);$foo->doSomething(); //C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|object(A)#10 (1) { ["b":"A":private]=> object(B)#14 (1) { ["c":"B":private]=> object(C)#16 (0) { } } } C::doSomething我是周伯通C|B::doSomething我是周伯通B|A::doSomething我是周伯通A|?>
以上代码的原理参考PHP官方文档:反射,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。
若想进一步提供一个数组访问接口,如$di->php7可以写成$di‘php7‘],则需用到[ArrayAccess(数组式访问)接口 。
一些复杂的容器会有许多特性,欢迎博友们补充。
php的依赖注入容器
原文地址:http://www.cnblogs.com/phpper/p/7781810.html