ThinkPHP6 核心分析(十一):Facade

说明

上一篇的例子中,User控制器引入了命名空间think\facade\Event,接着这样调用think\facade\Event::subscribe(),可打开think\facade\Event类的文件一看:

class Event extends Facade
{
    /**
     * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
     * @access protected
     * @return string
     */
    protected static function getFacadeClass()
    {
        return 'event';
    }
}

该类中只定义了一个getFacadeClass方法,是不存在subscribe方法的。程序实际调用的是think\Event类的subscribe方法,而且该方法也不是静态方法,在这里却是静态调用。这是如何做到的呢?

Facade的原理

Facade模式,中文一般翻译为「门面」模式,是指为一堆零散的风格不一的子系统设计一个统一的调用接口,这个接口就像是一个「门面」。Facade模式在这里的用处是把动态类方法转换为可静态调用的方法。接着,我们看看具体的实现过程。

think\facade\Event类继承了think\Facade类。查看think\Facade类,注意到其定义了一个魔术方法:

public static function __callStatic($method, $params)
{
    return call_user_func_array([static::createFacade(), $method], $params);
}

在PHP中,当一个类静态调用一个不存在的方法,将会触发该魔术方法,所以think\facade\Event::subscribe()这样调用的时候,首先是执行该__callStatic方法。
在这个例子中,该方法$method参数传入的值是subscribe$params传入的值是app\subscribe\User
先看看这其中的static::createFacade()方法:

protected static function createFacade(string $class = '', array $args = [], bool $newInstance = false)
{
    // 如果$class为空,那么$class就等于当前的类(think\facade\Event)
    $class = $class ?: static::class;
    // 解析出该Facade类实际要代理的类
    $facadeClass = static::getFacadeClass();

    if ($facadeClass) {
        $class = $facadeClass;
    }
    // 是否要一直新建实例(否则就是单例模式)
    if (static::$alwaysNewInstance) {
        $newInstance = true;
    }
    // 使用PHP的反射类实例化该类(比如,实例化think\Event)
    return Container::getInstance()->make($class, $args, $newInstance);
}

具体分析见注释。最后一个$newInstance参数可以设置是否使用单例模式。该方法最后返回一个类的对象(Facade类所代理的类),在本例子中是think\Event类的对象。

最后,程序执行call_user_func_array([static::createFacade(), $method], $params),在这个例子中,就等于执行:$obj->subscribe('app\subscribe\User')(其中,$objthink\Event类的一个对象)。

本作品采用《CC 协议》,转载必须注明作者和本文链接
Was mich nicht umbringt, macht mich stärker
讨论数量: 2

所以,什么情况下用 think\facade\Request ?或是 think\Request

4年前 评论
Fitz2015 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!