依赖注入
从应用程序的角度来讲,把依赖注入,应用程序依赖容器创建并注入它所需要的外部资源,
控制反转
从容器的角度来描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源
依赖注入与控制反转,其实是一个东西,描述角度不同而已,是一种设计模式
反射
通过类,获取知道他所依赖的类
容器
盛放对象的容器,通过容器调用类,会将类所需要的依赖都注入好,返回最终实例
三个类 A类依赖B类 B类依赖C类,互相继承或者引入的关系,耦合读很高,
使用依赖注入后,实例化调用 new A(new B(new C())) 定义层级关系了
使用容器,是直接用容器处理这些,有的容器需要自己手动处理这些关系,有的利用反射,自己实现,例子比较简单,PHP框架都使用了容器
<?php
class Bread
{
}
class Bacon
{
}
class Hamburger
{
protected $materials;
public function __construct(Bread $bread, Bacon $bacon)
{
$this->materials = [$bread, $bacon];
echo 1;
}
}
class Cola
{
}
class Meal
{
protected $food;
protected $drink;
public function __construct(Hamburger $hamburger, Cola $cola)
{
$this->food = $hamburger;
$this->drink = $cola;
echo 1;
}
}
//容器类
class Container
{
/**
* 获取类实例
*
* @param string $class
* @param array $params
* @return object
*/
public function make(string $class, array $params = [])
{
if (isset($this->binds[$class])) {
return ($this->binds[$class])->call($this, $this, ...$params);
}
return $this->resolve($class);
}
/**
* 通过反射获取对象
*
* @param $abstract
* @return object
* @throws ReflectionException
*/
protected function resolve($abstract)
{
// 获取反射对象
$constructor = (new ReflectionClass($abstract))->getConstructor();
// 构造函数未定义,直接实例化对象
if (is_null($constructor)) {
return new $abstract;
}
// 获取构造函数参数
$parameters = $constructor->getParameters();
$arguments = [];
foreach ($parameters as $parameter) {
// 获得参数的类型提示类
$paramClassName = $parameter->getClass()->name;
// 参数没有类型提示类,抛出异常
if (is_null($paramClassName)) {
throw new Exception('Fail to get instance by reflection');
}
// 实例化参数
$arguments[] = $this->make($paramClassName);
}
return new $abstract(...$arguments);
}
}
$ewew = new Container();
//返回的就是最终的对象
$ewew->make(Hamburger::class);