当前位置: 代码迷 >> 综合 >> tp5.1 Facade - 门面(四)
  详细解决方案

tp5.1 Facade - 门面(四)

热度:7   发布时间:2023-12-15 02:03:32.0

作用

门面为容器中的类提供了一个静态调用接口,相比传统了静态方式调用,带来了更好的可测试性和扩展性。

  代码使用 (这样写可以直接调用)两段代码执行的结果一样,实际执行的是在 \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);}