前言
經(jīng)過對依賴注入疏旨、控制反轉(zhuǎn)识椰、服務(wù)容器醇坝、服務(wù)提供者的了解后,對服務(wù)容器等有了初步的概念胧卤,可以簡單的將服務(wù)容器理解為一個在框架啟動時通過綁定的方式收納服務(wù)的一個數(shù)組武翎。這里就將服務(wù)容器的操作分為綁定篇及解析篇來進行記錄蛉腌。
正文
在Laravel的服務(wù)容器中提供了三種用于綁定的方法拓瞪,以及兩個用于存儲服務(wù)綁定關(guān)系的成員變量
instance方法會將綁定關(guān)系存在instances中
bind和singleton則將綁定關(guān)系存在bindings中
instance
將現(xiàn)有實例注冊到容器中缴罗,簡單說就是直接綁定已有的實例
//調(diào)用范例
$this->instance('app', $this);
public function instance($abstract, $instance)
{
//移除之前注冊過的別名
$this->removeAbstractAlias($abstract);
//獲取是否有過綁定,主要是對成員變量bindings祭埂,instances面氓,aliases進行isset判斷
$isBound = $this->bound($abstract);
//移除標示對應(yīng)的別名
unset($this->aliases[$abstract]);
//以傳入的$abstract為鍵,實例$instance為值存入成員變量instances中
$this->instances[$abstract] = $instance;
//判斷未經(jīng)過綁定
if ($isBound) {
//rebound主要做的是獲取當前標示($abstract)配置的回調(diào)進行執(zhí)行
$this->rebound($abstract);
}
return $instance;
}
protected function rebound($abstract)
{
//解析出實例蛆橡,具體解析會再后面的解析篇進行解讀
$instance = $this->make($abstract);
//獲取成員變量reboundCallbacks中是否存在為當前標示($abstract)配置的回調(diào)
//有的話則進行調(diào)用
//這里的回調(diào)一般都是在服務(wù)提供者內(nèi)部調(diào)用容器的rebinding方法進行配置的
foreach ($this->getReboundCallbacks($abstract) as $callback) {
call_user_func($callback, $this, $instance);
}
}
bind
向容器注冊綁定舌界,一般會以閉包的形式進行綁定,也有的會以命名空間+類名的形式進行綁定泰演,再bind方法內(nèi)部再通過命名空間+類名生成閉包
//調(diào)用范例
$this->bind('redis', function(){
return new Redis();
});
public function bind($abstract, $concrete = null, $shared = false)
{
//刪除所有舊的實例和別名
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
//如果$concrete傳的不是閉包呻拌,則在這里為其生成concrete閉包
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
//以 $abstract 為鍵,$concrete 和 $shared 合并成的數(shù)組為值睦焕, 賦值到 bindings 屬性中
$this->bindings[$abstract] = compact('concrete', 'shared');
//判斷 $abstract 標示是否存在與成員變量instances(通過instance進行綁定)
//和resolved(當被解析過后resolved中會存$abstract => true)中
//簡單說就是滿足上面其中之一后就說明這個綁定的實例已經(jīng)經(jīng)過實例化了
if ($this->resolved($abstract)) {
//rebound主要做的是獲取當前標示($abstract)配置的回調(diào)進行執(zhí)行
$this->rebound($abstract);
}
}
//獲取閉包
protected function getClosure($abstract, $concrete)
{
//閉包內(nèi)的代碼只有調(diào)用是才會執(zhí)行
return function ($container, $parameters = []) use ($abstract, $concrete) {
//值相同的時候通過反射類進行實例獲取
if ($abstract == $concrete) {
return $container->build($concrete);
}
//如果不相同則會根據(jù)$concrete再次進行解析
return $container->resolve(
$concrete, $parameters, $raiseEvents = false
);
};
}
singleton
在容器中注冊共享綁定
該方法其實就是在內(nèi)部調(diào)用了bind藐握,再調(diào)用時將第三個參數(shù)寫死為true,以單例的方式進行綁定
//調(diào)用范例
$this->singleton('redis', function(){
return new Redis();
});
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
END