🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[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方法。