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');