作用
门面为容器中的类提供了一个静态调用接口,相比传统了静态方式调用,带来了更好的可测试性和扩展性。
代码使用 (这样写可以直接调用)两段代码执行的结果一样,实际执行的是在 \think\Facade\Config
$apps = \Config::get('app.');
halt($apps);$apps = \think\Facade\Config::get('app.');
halt($apps);
为什么可以使用 \Config 就可以调用呢?在 base.php中注册了类的别名,所以就可以使用 Config 来调用
// 注册类库别名
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,
]);
看来分析代码
1、可以看到在 thinkphp/library/think/facade/Config.php 中
class Config extends Facade
{/*** 获取当前Facade对应类名(或者已经绑定的容器对象标识)* @access protected* @return string*/protected static function getFacadeClass(){return 'config';}
}
2、看继承的 facade 类 =》 thinkphp/library/think/facade.php文件
class Facade
{/*** 绑定对象* @var array*/protected static $bind = [];/*** 始终创建新的对象实例* @var bool*/protected static $alwaysNewInstance;/*** 绑定类的静态代理* @static* @access public* @param string|array $name 类标识* @param string $class 类名* @return object*/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;}}/*** 创建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);}/*** 获取当前Facade对应类名(或者已经绑定的容器对象标识)* @access protected* @return string*/protected static function getFacadeClass(){}/*** 带参数实例化当前Facade类* @access public* @return mixed*/public static function instance(...$args){if (__CLASS__ != static::class) {return self::createFacade('', $args);}}/*** 调用类的实例* @access public* @param string $class 类名或者标识* @param array|true $args 变量* @param bool $newInstance 是否每次创建新的实例* @return mixed*/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);}// 调用实际类的方法public static function __callStatic($method, $params){return call_user_func_array([static::createFacade(), $method], $params);}
}
可以看到是没有get 静态方法的,那么他是如何调用的。
1、执行第一步,使用魔术方法 __callStatic() 。
2、执行 static::createFacade() 函数,使用 Container 获取当前调用类的对象。
3、执行,call_user_func_array 是 php 内置函数,并使用对象调用 对应的 方法执行代码,并返回结果。
createFacade 方法解析
/*** 创建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(); // configif ($facadeClass) {$class = $facadeClass; // 存在的话 $class = config} elseif (isset(self::$bind[$class])) { //看看 self::$bind 是否存在 config$class = self::$bind[$class];}if (static::$alwaysNewInstance) {$newInstance = true;}// 使用容器获取对象实列return Container::getInstance()->make($class, $args, $newInstance);}