首先我们来一个实例,上代码
<?php class A { public function test() { echo 'this is A!<br>'; $b = new B(); $b->test(); } } class B { public function test() { echo 'this is B!<br>'; $c = new C(); $c->test(); } } class C { public function test() { echo 'this is C!<br>'; } } $obj = new A(); $obj->test();
结果是:
this is A! this is B! this is C!
从代码分析,A类依赖B类,B类依赖C类。这是我们最原始的实现思路.这种实现思路很明显会有问题
假如我们现在B类修改下,代码如下:
class B { public $name; public function __construct($name) { $this->name = $name; } public function test() { echo 'this is B'.$this->name.'!<br>'; $c = new C(); $c->test(); } }
此时再看我们原来A类test方法直接调用明显会有问题,于是此时我们需要将原来代码:
class A { public function test() { echo 'this is A!<br>'; $b = new B(); $b->test(); } }
修改成:
class A { public function test() { echo 'this is A!<br>'; $b = new B('(class B)');//构造的时候多加了一个参数 $b->test(); } }
如果此时C类构造方法也变动了呢,B的方法里面也同样受影响,很明显可用性非常低
为了解耦,此时我们用到第二种思路:构造器注入,直接上代码:
<?php class A { public $obj; public function __construct(B $b) { $this->obj = $b; } public function test() { echo 'this is A!<br>'; $this->obj->test(); } } class B { public $obj; public function __construct(C $c) { $this->obj = $c; } public function test() { echo 'this is B!<br>'; $this->obj->test(); } } class C { public function test() { echo 'this is C!<br>'; } } $c = new C(); $b = new B($c); $obj = new A($b); $obj->test();
这种方法可以解决第一种方法,如果依赖的类构造方法(比如B类)有所改动,A类不需要改动任何代码。但是久而久之,这种方法毛病也出来了,我们首先必须要先实例化C类,再实例化B类,最后再实例化A类。
了解到第二种方案需要优化,于是出现了基本成型的第三种方案,此时我们用到了container(容器)和instance(实例),直接上代码:
class Container { public static $_classes = []; public static $_definations = []; public function get($class) { if(isset(self::$_classes[$class])) return self::$_classes[$class]; //当前类所依赖的类 $depends = []; $tc = new ReflectionClass($class); //得到构造方法 $constructor = $tc->getConstructor(); //得到构造方法的参数 if($constructor !== NULL) { foreach($constructor->getParameters() as $parameter) { if($parameter->isDefaultValueAvailable()) { $depends[] = $parameter->getDefaultValue(); } else { $pc = $parameter->getClass(); $instance = Instance::getInstance($pc == NULL ? NULL : $pc->getName()); $depends[] = $instance; } } } foreach($depends as $k => $v) { if($v instanceof Instance) { if($v->id !== NULL) { $depends[$k] = $this->get($v->id); } } } $tm_instance = $tc->newInstanceArgs($depends); self::$_classes[$class] = $tm_instance; return $tm_instance; } } class Instance{ /** * @var 类唯一标示 */ public $id; /** * 构造函数 * @param string $id 类唯一ID * @return void */ public function __construct($id) { $this->id = $id; } /** * 获取类的实例 * @param string $id 类唯一ID * @return Object Instance */ public static function getInstance($id) { return new self($id); } } class Base{ /** * 魔术方法 * @param string $name * @param string $value * @return void */ public function __set($name, $value) { $this->{$name} = $value; } } class A extends Base{ private $instanceB; public function __construct(B $instanceB) { $this->instanceB = $instanceB; } public function test() { echo 'this is A!<br/>'; $this->instanceB->test(); } } class B extends Base{ private $instanceC; public function __construct(C $instanceC) { $this->instanceC = $instanceC; } public function test() { echo 'this is B!<br/>'; return $this->instanceC->test(); } } class C extends Base{ public function test() { echo 'this is C!'; } } $container = new Container(); $obj_a = $container->get('A'); $obj_a->test();
此方法有参考yii2中yii2\di\container实现,只是将它简化了,更容易看懂。重点看看container的get方法
原文地址:http://blog.51cto.com/chinalx1/2106072