一、初步探索
控制反转,反转是相对于正转来说的,下面是正转的代码
class A{
public function __construct(){
$this->b = new B();
}
public function aMethod(){
return $this->b->bMethod();
}
}
class B{
public function __construct(){}
public function bMethod(){
return 12;
}
}
$b = (new A)->aMethod();
A类中的代码需要依赖B类,然后我们就在A的代码中实例化B类,然后调用B类中的方法
缺点:如果有多个地方需要用到B的实例化对象的话,就需要复制多次该代码
控制反转的代码
class A{
protected $b;
public function __construct(B $b){
$this->b = $b;
}
public function getB(){
return $this->b->abc();
}
}
class B{
public function __construct(){}
public function abc(){
echo 23;
}
}
class Ioc{
protected $instance = [];
public function __construct(){
$this->instances['B'] = new B();
$this->instances['C'] = new C();
$this->instances['D'] = new D();
}
public function make(string $abstract){
return $this->instances[$abstract];
}
}
echo '
'
$ioc = new Ioc();
$b = $ioc->make('B');
$a = new A($b);
$a->getB();
控制反转在外部处理好依赖关系,不需要在A中直接new B,而是让IoC容器将B给我,这就叫控制反转IoC
书面解释:将组件间的依赖关系从程序内部提到外部来管理。控制反转是站在A的立场来看的,它是拿B的
控制反转是说创建对象的控制权进行转移,以前创建对象的主动权和创建时机是自己把控的,而现在这种权利转移到第三方,比如转移交给了IoC容器,它是一个专门用来创建对象的工厂(BeanFactory),你要什么对象他就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,他们都依赖IoC容器里,通过ioc容器来建立他们之间关系
书面解释:组件间的依赖通过外部以参数或其他形式注入就是依赖注入DI,依赖注入是站在IoC立场上来看的,它是送B的
依赖 注入:IoC/DI容器注入某个对象所需要的外部资源
控制 反转:IoC/DI容器控制对象、控制对象实例的创建,主动权的转移
缺点明显:
1、无法提前生成所有的实例化对象
2、没有解决多层依赖的问题,仅仅是将依赖关系从程序内部提到了外部管理
二、进一步探索
在PHP运行时,扩展分析程序,导出或提出关于类、方法、属性、参数等的详细信息,包括注释。这种动态获取信息以及动态调用方法的功能称为反射API
class A{
public function __construct(B $b){
$this->b = $b;
}
public function getB(){
$this->b->bMethod();
}
}
class B{
public function __construct(C $c, D $d){
$this->c = $c;
$this->d = $d;
}
public function bMethod(){
echo '我是B中的方法bMethod()';
}
}
class C{
public function __construct(){}
public function cMethod(){
echo '我是C中的方法cMethod()';
}
}
class D{
public function __construct(){}
public function dMethod(){
echo '我是B中的方法dMethod()';
}
}
class Ioc{
protected $instance = [];
public function __construct(){}
public function getInstance($abstract){
//获取类的反射信息,也就是类的所有信息
$reflector = new ReflectionClass($abstract);
//echo $reflector->getDocComment();//获取类的注释信息
//获取反射类的构造函数信息
$constructor = $reflector->getConstructor();
//获取反射类的构造函数的参数
$dependencies = $constructor->getParameters();
if(!$dependencies){
return new $abstract();
}
//一个类可能有多个依赖类
foreach ($dependencies as $dependency){
if(!is_null($dependency->getClass())){
$p[] = $this->make($dependency->getClass()->name);
//这里$p[0]是c的实例化对象,$p[1]是D的实例化对象
}
}
//创建一个类的新实例,给出的参数将传递到类的构造函数
//构造出B的实例化对象,向上反推到A的实例化对象
return $reflector->newInstanceArgs($p);
}
public function make($abstract){
return $this->getInstance($abstract);
}
}
$ioc = new Ioc();
$a = $ioc->make('A');
$a->getB();