作用
门面为容器中的类提供了一个静态调用接口,相比传统了静态方式调用,带来了更好的可测试性和扩展性。
代码使用 (这样写可以直接调用)两段代码执行的结果一样,实际执行的是在 \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(); // config
if ($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);
}