[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方法。