namespace Illuminate\Container;
use Closure; // "PHP 默认闭包类"
use Exception; // "异常处理类"
use ArrayAccess; // "对象按数组方式调用类"
use LogicException;
use ReflectionClass; // "反射类"
use ReflectionParameter; // "反射参数类"
use Illuminate\Support\Arr; // "边界数组访问类"
use Illuminate\Contracts\Container\BindingResolutionException; // "绑定结果异常类"
use Illuminate\Contracts\Container\Container as ContainerContract; // "容器契约"
class Container implements ArrayAccess, ContainerContract
复制代码
容器实现了ArrayAccess接口兼容以数组调用的方式来读取属性。laravel
Container 的成员
protected static $instance; // "Application 实例"
protected $resolved = []; // "已解析的类型的数组"
protected $bindings = []; // "容器中的绑定数组"
protected $methodBindings = []; // "容器中的方法绑定"
protected $instances = []; // "容器中的共享实例"
protected $aliases = []; // "类的别名"
protected $abstractAliases = []; // "类的别名"
protected $extenders = []; //
protected $tags = []; // "全部注册的标签"
protected $buildStack = []; // "build进行中的具体类"
protected $with = []; // "build中须要的构造函数参数"
public $contextual = []; // "构建类的上下文环境"
protected $reboundCallbacks = [];
protected $globalResolvingCallbacks = []; // "容器全局须要在解析对象过程当中调用的回调"
protected $globalAfterResolvingCallbacks = []; // "容器全局须要在解析后调用的回调"
protected $resolvingCallbacks = []; // "针对指定的类在解析的时候调用的回调"
protected $afterResolvingCallbacks = [];// "针对指定的类在解析后的时候调用的回调"
复制代码
绑定抽象名和具体类的方法
public function bind($abstract, $concrete = null, $shared = false)
{
// "从 $instances 和 $aliases 清理旧的绑定信息"
$this->dropStaleInstances($abstract);
// "若是没有传入具体类,则将抽象名赋值给具体类"
if (is_null($concrete)) {
$concrete = $abstract;
}
// "若是具体类不是闭包对象,则进行一层包装"
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
// "将闭包对象$concrete和$shared赋值到bindings中的抽象名下"
$this->bindings[$abstract] = compact('concrete', 'shared');
// "若是抽象名已经被解析过实例,则进行从新绑定"
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
}
复制代码
根据给定的类获取实例
public function build($concrete)
{
// "若是是闭包则直接执行本身获取实例"
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
// "获取具体类的反射"
$reflector = new ReflectionClass($concrete);
// "若是类不能够实例化则抛出异常"
if (! $reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
}
// "将类放入构建堆栈中"
$this->buildStack[] = $concrete;
// "获取类的构造函数"
$constructor = $reflector->getConstructor();
// "若是没有构造函数,直接从 buildStack 堆栈中 pop 出的同时返回新对象"
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
// "获取构造函数依赖变量"
$dependencies = $constructor->getParameters();
// "解析全部须要的变量包括对象 (DI就是这么实现的!)"
$instances = $this->resolveDependencies(
$dependencies
);
// "弹出堆栈中待构建的类"
array_pop($this->buildStack);
// "根据参数实例化类并返回"
return $reflector->newInstanceArgs($instances);
}
复制代码
根据传入的抽象名和参数解析出相对的具体类
protected function resolve($abstract, $parameters = [])
{
// "若是存在别名则返回,不然返回抽象"
$abstract = $this->getAlias($abstract);
// "存在参数或者给定抽象的上下文绑定则复制给变量"
// "上下文绑定实现指 $abstractAliases 中的绑定关系"
$needsContextualBuild = ! empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract)
);
// "若是是个单例实例则能够直接返回已经存在的实例。"
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}
// "将须要的参数放入 $with 中"
$this->with[] = $parameters;
// "从$bindings中获取抽象对应的具体类"
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
// "若是具体类是闭包或者和抽像同名的时候直接实例化这个类"
$object = $this->build($concrete);
} else {
// "递归套嵌的依赖,知道全部的依赖被解析实例化。"
$object = $this->make($concrete);
}
// "若是此类定义了拓展,则将该构建中的对象进行拓展和修饰。这容许更改配置或者修饰对象"
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
// "若是是单例类,直接将实例放入内存,防止后续重复实例化。"
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}
// "调用全部全局待解析的回调和指定抽象的回调"
$this->fireResolvingCallbacks($abstract, $object);
// "标识此抽象已经被解析完毕。"
$this->resolved[$abstract] = true;
// "with中的数据出栈"
array_pop($this->with);
// "返回解析完毕的实例"
return $object;
}
复制代码
目前只是分析比较核心的方法数组
bind() 方法负责把抽象和具体类绑定到$bindings成员中。
复制代码
build() 方法负责具体类中反射出须要的参数构造实例并返回。
复制代码
resolve()方法则是将抽象从$aliases中查找别名,
而后从$bindings获取具体类,最后调用build()方法来构造类,
或者继续递归本身来构造类的依赖。其中还包含拓展类以及执行全部回调。
同时若是是单例的类则在构造完成后存入$instances,
下次调用则直接从$instances返回实例。
复制代码