1. 程式人生 > >談談thinkphp5.1中容器(Container)和門面(Facade)的實現【轉載】

談談thinkphp5.1中容器(Container)和門面(Facade)的實現【轉載】

// thinkphp\library\facade\Config 類
namespace think\facade;

use think\Facade;

class Config extends Facade
{
}
// 從原始碼上看 Config本身沒有任何方法,它繼承了Facade的方法,但Facade並沒有get這個靜態方法
// 此時,系統自動觸發了魔術方法:__callStatic(),Facade重寫了此方法:
public static function __callStatic($method, $params)
{
return call_user_func_array([static::createFacade(), $method], $params);
}
// 可見,最後呼叫的是使用者自定義函式:call_user_func_array([例項, 方法], 引數),為了獲得Config例項,Facade又定義了一個獲取物件的方法:
/**
* 建立Facade例項
* @static
* @access protected
* @param string $class 類名或標識
* @param array $args 變數
* @param bool $newInstance 是否每次建立新的例項
* @return object
*/
protected static function createFacade($class = '', $args = [], $newInstance = false)
{
$class = $class ?: static::class;
$facadeClass = static::getFacadeClass();

if ($facadeClass) {
$class = $facadeClass;
} elseif (isset(self::$bind[$class])) {
$class = self::$bind[$class];
}

if (static::$alwaysNewInstance) {
$newInstance = true;
}

return Container::getInstance()->make($class, $args, $newInstance);
}
// 其內部是通過容器來例項化物件
// 因為在base.php中已經將 think\Config 類繫結到 config 這個標識
Container::getInstance()->bind([
  'config' => Config::class
])

// 在
createFacade 方法中,獲取類的名稱:$class = $class ?: static::class; 即得到 config 這個標識
// 在容器的make方法中,根據config標識,找到繫結的 think\Config 類,並呼叫其動態方法 get。

facade\Config::get('app_debug');

// 最後呼叫的是:

(new think\Config())->get('app_debug');