// 容器类,将接口与实现绑定
class Container{
// 保存与接口绑定的闭包,
// 闭包必须能够返回接口的实例。
protected $bindings = [];
// 为某个接口绑定一个实现,有两种情况: <br /> // 第一种是绑定接口的实现的类名;
// 第二种是绑定一个闭包,这个闭包应该返回接口的实例。
// 不管哪种情况,实例化操作都是调用 build() 方法完成。
// 第二种情况,主要是为了能够在实例化前后进行额外的操作,
// 实例化的逻辑就书写在闭包中。
public function bind($abstract, $concrete = null)
{
// 如果提供的参数不是闭包,而是一个类,
// 则构建一个闭包,直接调用 build() 方法进行实例化
if (! $concrete instanceof Closure) {
// 调用闭包时,传入的参数是容器本身,即
$this
$concrete = function ($c) use ($concrete) {
return $c->build($concrete);
};
}
$this->bindings[$abstract] = $concrete;
}
// 生成指定接口的实例
public function make($abstract)
{
// 取出闭包
$concrete = $this->bindings[$abstract];
// 运行闭包,即可取得一个实例
return $concrete($this);
}
public function build($class)
{
// 取得类的反射
$reflector = new ReflectionClass($class);
// 检查类是否可实例化
if (! $reflector->isInstantiable()) {
// 如果不能,意味着接口不能正常工作,报错
echo $message = “Target [$class] is not instantiable”;
}
// 取得构造函数的反射
$constructor = $reflector->getConstructor();
// 检查是否有构造函数
if (is_null($constructor)) {
// 如果没有,就说明没有依赖,直接实例化
return new $class;
}
// 取得包含每个参数的反射的数组
$parameters = $constructor->getParameters();
// 返回一个真正的参数列表,那些被类型提示的参数已经被注入相应的实例
$realParameters = $this->resolveDependencies($parameters);
return $reflector->newInstanceArgs($realParameters);
}
//解决依赖 支持数组 注入
protected function resolveDependencies($parameters){
$realParameters = [];
foreach($parameters as $parameter) {
// 如果一个参数被类型提示为类 foo,
// 则这个方法将返回类 foo 的反射
$dependency = $parameter->getClass();
if(is_null($dependency)) {
$realParameters[] = NULL;
} else {
$realParameters[] = $this->make($dependency->name);
}
}
return (array)$realParameters;
}
}
原文简化版
https://learnku.com/articles/4076/how-to-understand-laravels-ioc-container