[TOC]
* * * * *
## 1 Facade實現
### 0 實現文件
~~~
/lirary/think/Facade.php
~~~
### 1 核心方法
#### bind() 注冊類的靜態代理
~~~
public static function bind($name, $class = null)
{
if (__CLASS__ != static::class) {
return self::__callStatic('bind', func_get_args());
}
if (is_array($name)) {
self::$bind = array_merge(self::$bind, $name);
} else {
self::$bind[$name] = $class;
}
}
~~~
> 與Container的bind類似。
> 注冊類標識與類名的對應關系。
#### make() 創建類的實例
~~~
public static function make($class, $args = [], $newInstance = false)
{
if (__CLASS__ != static::class) {
return self::__callStatic('make', func_get_args());
}
if (true === $args) {
// 總是創建新的實例化對象
$newInstance = true;
$args = [];
}
return self::createFacade($class, $args, $newInstance);
}
~~~
> 創建類對應的實例對象
### 2 底層實現
#### createFacade() 類的實例創建
~~~
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);
}
~~~
> * 獲取要創建的類名
> 1. 檢測傳入的參數$class。為空則為Facade類
> 2. 調用Facade的getFacadeClass()實現獲取類名
> * 讀取Facade中bind的對應的具體類。
> * 調用Container的make創建新的對象實例。
> 創建類的實例對象。
> 這是靜態調用實例方法的的第一步。
#### __callStatic() 靜態調用實例的方法
~~~
public static function __callStatic($method, $params)
{
return call_user_func_array([static::createFacade(), $method], $params);
}
~~~
> * 調用createFacade()創建類的實例。
> * 使用call_user_func_array()調用實例的方法
> 這里在靜態調用中具體調用了實例對象的方法。
> 這是靜態調用實例方法的第二步。
> 通過以上兩步,實現了靜態調用對象實例的方法。
## 2 facade目錄
> 在library/think/facade/目錄中實現了核心類的facade代理
~~~
// think/facade/App.php
namespace think\facade;
use think\Facade;
class App extends Facade
{
}
~~~
> 文件內容基本一致。都是一個繼承Facade的類定義。
> 這樣就可以實現類的靜態代理
## 3 核心類庫的Facade靜態代理
> 在base.php中注冊了核心類庫的Facade代理
~~~
// base.php
Facade::bind([
facade\App::class => App::class,
facade\Build::class => Build::class,
facade\Cache::class => Cache::class,
facade\Config::class => Config::class,
facade\Cookie::class => Cookie::class,
facade\Debug::class => Debug::class,
facade\Env::class => Env::class,
facade\Hook::class => Hook::class,
facade\Lang::class => Lang::class,
facade\Log::class => Log::class,
facade\Request::class => Request::class,
facade\Response::class => Response::class,
facade\Route::class => Route::class,
facade\Session::class => Session::class,
facade\Url::class => Url::class,
facade\Validate::class => Validate::class,
facade\View::class => View::class,
]);
~~~
>[info] 這里將facade子目錄下的靜態代理類與核心類庫對應關系注冊到Facade的bind中。
>
>在調用facade\Cookie中的靜態方法時,則具體調用Cookie實例對象的具體方法
>
>接著注冊代理類名的別名
~~~
Loader::addClassAlias([
'App' => facade\App::class,
'Build' => facade\Build::class,
'Cache' => facade\Cache::class,
'Config' => facade\Config::class,
'Cookie' => facade\Cookie::class,
'Db' => Db::class,
'Debug' => facade\Debug::class,
'Env' => facade\Env::class,
'Facade' => Facade::class,
'Hook' => facade\Hook::class,
'Lang' => facade\Lang::class,
'Log' => facade\Log::class,
'Request' => facade\Request::class,
'Response' => facade\Response::class,
'Route' => facade\Route::class,
'Session' => facade\Session::class,
'Url' => facade\Url::class,
'Validate' => facade\Validate::class,
'View' => facade\View::class,
]);
~~~
>[info] 注冊靜態代理類到根命名空間的具體類中。
>這樣就可以使用 5.1手冊中的 根命名空間類調用核心類對象的方法
~~~
\Cache::set('name','value');
echo \Cache::get('name');
~~~
> 上面的\Cache的靜態調用就是調用facade\Cache的靜態調用。
> facade\Cache的靜態則調用核心類庫think\Cache的實例對象的set方法。