13
07月
2020
门面为容器中的类提供了一个静态调用接口;
相对于传统的静态调用带来了更好的可测试性和扩展性;
例:
facade\Config::get('app_debug');
thinkphp/library/think/facade/Config.php
<?php namespace think\facade; use think\Facade; /** * @see \think\Config * @mixin \think\Config * @method array load(string $file, string $name = '') static 加载配置文件 * @method bool has(string $name) static 检测配置是否存在 * @method array pull(string $name) static 获取一级配置参数 * @method mixed get(string $name,mixed $default = null) static 获取配置参数 * @method array set(mixed $name, mixed $value = null) static 设置配置参数 * @method array reset(string $name ='') static 重置配置参数 * @method void remove(string $name = '') static 移除配置 * @method void setYaconf(mixed $yaconf) static 设置开启Yaconf 或者指定配置文件名 */ class Config extends Facade { /** * 获取当前Facade对应类名(或者已经绑定的容器对象标识) * @access protected * @return string */ protected static function getFacadeClass() { return 'config'; } }
Config本身没有任何方法,它继承了Facade的方法,但Facade并没有get这个静态方法 此时,系统自动触发了魔术方法:__callStatic()
thinkphp/library/think/Facade.php
<?php namespace think; class 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); } ...... // 调用实际类的方法 public static function __callStatic($method, $params) { // 最后调用的是用户自定义函数:call_user_func_array([实例, 方法], 参数) // 调用 createFacade() 方法 return call_user_func_array([static::createFacade(), $method], $params); } }
在 createFacade 方法中,获取类的名称:$class = $class ?: static::class; 即得到 config 这个标识,在容器的make方法中,根据config标识,找到绑定的 think\Config 类,并调用其动态方法 get
最后调用的是:
(new think\Config())->get('app_debug');