TP5.1的核心代码解析之Facade

Facade是什么呢,目前看是一个用来方便实现原有类(未定义静态方法)的静态方式调用对应的方法的类。
具体Facade的实现如下:
首先看核心文件:

\thinkphp\base.php

中的:

// 注册核心类的静态代理
Facade::bind([
    facade\App::class      => App::class,
    facade\Build::class    => Build::class,
    facade\Cache::class    => Cache::class,
    facade\Config::class   => Config::class,
    facade\Cookie::class   => Cookie::class,
    facade\Debug::class    => Debug::class,
    facade\Env::class      => Env::class,
    facade\Hook::class     => Hook::class,
    facade\Lang::class     => Lang::class,
    facade\Log::class      => Log::class,
    facade\Request::class  => Request::class,
    facade\Response::class => Response::class,
    facade\Route::class    => Route::class,
    facade\Session::class  => Session::class,
    facade\Url::class      => Url::class,
    facade\Validate::class => Validate::class,
    facade\View::class     => View::class,
]);

可以看到类似容器中的绑定方式,找到对应的绑定方法如下:

   /**
     * 绑定类的静态代理
     * @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;
        }
    }

可以看到同样是放到了一个数组$bind中。
这里注意一下下面的在\thinkphp\base.php文件中的注册类别名的方法,可以实现类别名直接访问类(这里自己看)

// 注册类库别名
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,
]);

那么具体如何调用的静态方法呢,比如

\Cache::set('name','value');

这个方法,具体时间如何调用到set方法呢,首先先用上面的类的别名机制直接找到对应的facade\Cache::class这个类,也就是实际上是调用的这个类。然后我们看这个类的内容:

namespace think\facade;

use think\Facade;

class Cache extends Facade
{
}

可以看到没有内容,那set方法哪来的呢,这里利用了一个PHP的静态方法调用失败会调用的方法,在Facade类中有:

 // 调用实际类的方法
    public static function __callStatic($method, $params)
    {
        return call_user_func_array([static::createFacade(), $method], $params);
    }
//在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。    

也就是当调用不到set方法时,这个方法会被调用,也就是实际上调用了

call_user_func_array([static::createFacade(), $method], $params)

实际上就是:

/**
     * 创建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);
    }

可以看到最后一句,实际上也就是是调用了Cache::class的实例(通过容器获取)的set方法。

以上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值