ThinkPHP容器之容器是如何返回範例的

2020-10-12 15:00:51

在之前的文章中我們簡單的梳理了一下容器類,接下來就是對其中一個細節進行深度分析。

Container範例呼叫make方法

本文沒有太多文字解析,都在程式碼註釋中說明了執行過程。

程式碼static::getInstance()返回了Container的範例後,就會去呼叫本類的make方法,接下來就是對make方法進行詳解了。

在開始閱讀make方法裡邊的原始碼之前,我們需要先對幾個屬性進行簡單的梳理一下。

這四個屬性一定要有點印象,並且一定要區別instance和instances。

這倆個屬性一個是單例模式返回當前類的範例,一個是容器中的所有的範例。

第一次執行結果

   /**
* 建立類的範例
* @access public
* @param string $abstract 類名或者標識
* @param array|true $vars 變數
* @param bool $newInstance 是否每次建立新的範例
* @return object
*/

public function make($abstract, $vars = [], $newInstance = false)
{
// 判斷$vars這個變數是否為true
if (true === $vars) {
// 總是建立新的範例化物件
$newInstance = true;
$vars = [];
}

// app 這裡就是在容器別名裡獲取傳遞過來的app 如果沒有則就是app
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;

// 從容器範例中獲取 如果存在則直接返回對應的範例 也就是使用註冊樹模式
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}

// think\App 從容器標識中獲取
if (isset($this->bind[$abstract])) {
// 將think\App 複製給$concrete變數
$concrete = $this->bind[$abstract];
// 用於代表匿名函數的類 判斷是不是閉包
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// $this->name['app'] = think\App
$this->name[$abstract] = $concrete;
// 在執行一次本類的make方法,也就是本方法
return $this->make($concrete, $vars, $newInstance);
}
} else {
$object = $this->invokeClass($abstract, $vars);
}

if (!$newInstance) {
$this->instances[$abstract] = $object;
}

return $object;
}

這是第二次執行流程

    public function make($abstract, $vars = [], $newInstance = false)
{
// 判斷$vars這個變數是否為true
if (true === $vars) {
// 總是建立新的範例化物件
$newInstance = true;
$vars = [];
}

// app 這裡就是在容器別名裡獲取傳遞過來的app 如果沒有則就是app
// 第二次執行時 $abstract = think\App
$abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;

// 從容器範例中獲取 如果存在則直接返回對應的範例 也就是使用註冊樹模式
if (isset($this->instances[$abstract]) && !$newInstance) {
return $this->instances[$abstract];
}

// think\App 從容器標識中獲取
// 第二次執行$this->bind['think\App']不存在走else
if (isset($this->bind[$abstract])) {
// 將think\App 複製給$concrete變數
$concrete = $this->bind[$abstract];
// 用於代表匿名函數的類 判斷是不是閉包
if ($concrete instanceof Closure) {
$object = $this->invokeFunction($concrete, $vars);
} else {
// $this->name['app'] = think\App
$this->name[$abstract] = $concrete;
// 在執行一次本類的make方法,也就是本方法
// think\App
return $this->make($concrete, $vars, $newInstance);
}
} else {
// think\App
$object = $this->invokeClass($abstract, $vars);
}

if (!$newInstance) {
// 把建立的容器存起來
//$this->instances['think\App'] = $object;
$this->instances[$abstract] = $object;
}

return $object;
}
public function invokeClass($class, $vars = [])
{
try {

/**
* ReflectionClass Object
(
[name] => think\App
)
*/

// 這裡就是之前文章提到的反射
$reflect = new ReflectionClass($class);


if ($reflect->hasMethod('__make')) {
$method = new ReflectionMethod($class, '__make');

if ($method->isPublic() && $method->isStatic()) {
$args = $this->bindParams($method, $vars);
return $method->invokeArgs(null, $args);
}
}
// 通過反射獲取think\App的建構函式
$constructor = $reflect->getConstructor();

$args = $constructor ? $this->bindParams($constructor, $vars) : [];
// 從給出的引數建立一個新的類範例
return $reflect->newInstanceArgs($args);

} catch (ReflectionException $e) {
throw new ClassNotFoundException('class not exists: ' . $class, $class);
}
}

執行流程圖

既然把程式碼都理清楚了,這時來理一下執行的流程圖可以看的更清晰。

堅持學習、堅持寫博、堅持分享是咔咔從業以來一直所秉持的信念。希望在偌大網際網路中咔咔的文章能帶給你一絲絲幫助。我是咔咔,下期見。

以上就是ThinkPHP容器之容器是如何返回範例的的詳細內容,更多請關注TW511.COM其它相關文章!