门面模式的作用是使一个全部都是非静态方法的类无需实例化就能直接通过静态方式调用该类里面的方法(好无聊好鸡肋...)。
以TP5的门面模式为例:
Tp5的门面基类在\thinkphp\library\think\Facade.php中。Tp5的Config、Cookie、Session、Cache、Url等等的内置类都有对应的门面类,这些门面类都会继承自门面基类。
例如:
Tp5中的Cache内置类位于:
\thinkphp\library\think\Cache.php (里面的方法大多都是一些非静态方法)
Cache内置类的门面类位于:
\thinkphp\library\think\facade\Cache.php (里面只有一个getFacadeClass方法)
门面类的运行逻辑如下:
原类Test -> 门面类Test -> 门面基类Facade
1、假如你自定义了一个类 app\Common\Test,想用静态方法的调用方式调用其非静态方法,就需要定义一个门面类app\Facede\Test。
2、门面类Test可以定义在 app目录下的任何地方,一般会我们需要建一个 app/Facade目录用来放所有我们自定义的门面类。
3、自定义的门面类Test要继承自 think\Facade门面类,而且Test须定义一个getFacadeClass()类告诉基类Facade,本门面类Test的原类是 app\Common\Test类。getFacadeClass方法起到一个绑定门面类Test和原类Test的作用。
class Test extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\Test';
}
}
此外也可以不定义getFacadeClass方法,而是调用 Facade类的bind方法绑定。
Facade::bind([
'app\facade\Test' => 'app\common\Test',
'app\facade\Info' => 'app\common\Info',
]);
4、当我们要调用原类Test的方法时,直接用门面类Test调用即可。
$res = \app\Facade\Test::say();
执行静态调用时,由于不存在该静态方法,因此会触发Facade类内部的__callStatic()魔术方法,该魔术方法内部会从IOC容器获取一个原类Test的实例,并实际调用Test实例的say()方法。
门面基类Facade的逻辑:
bind的逻辑:将Test原类和Test门面类的映射关系保存到一个self::$bind的数组中。
当Test门面类用静态方法的调用方式调用其非静态方法say():会触发__callStatic方法,该方法内会通过 getFacadeClass() 或者self::$bind中取得原类类名,通过IOC容器实例化一个原类的实例,并调用其非静态方法say()。
之后每次门面类Test调用静态方法,都会从IOC取出这个原类复用。