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返回實例。
複製代碼