上一篇的例子中,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模式在这里的用处是把动态类方法转换为可静态调用的方法。接着,我们看看具体的实现过程。
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')
(其中,$obj
是think\Event
类的一个对象)。
Bug天天改,头发日日疏,码字不易,如果有帮助到你,就点击"下方感谢"支持一下把.