首先我们来一个实例,上代码
<?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