Facade

优质
小牛编辑
159浏览
2023-12-01

门面(Facade

门面为容器中的类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,你可以为任何的非静态类库定义一个facade类。

系统已经为大部分核心类库定义了Facade,所以你可以通过Facade来访问这些系统类,当然也可以为你的应用类库添加静态代理。

下面是一个示例,假如我们定义了一个app\common\Test类,里面有一个hello动态方法。

<?php
namespace app\common;

class Test
{
    public function hello($name)
    {
        return 'hello,' . $name;
    }
}

调用hello方法的代码应该类似于:

$test = new \app\common\Test;
echo $test->hello('thinkphp'); // 输出 hello,thinkphp

接下来,我们给这个类定义一个静态代理类app\facade\Test(这个类名不一定要和Test类一致,但通常为了便于管理,建议保持名称统一)。

<?php
namespace app\facade;

use think\Facade;

class Test extends Facade
{
    protected static function getFacadeClass()
    {
        return 'app\common\Test';
    }
}

只要这个类库继承think\Facade,就可以使用静态方式调用动态类app\common\Test的动态方法,例如上面的代码就可以改成:

// 无需进行实例化 直接以静态方法方式调用hello
echo \app\facade\Test::hello('thinkphp');

结果也会输出 hello,thinkphp

说的直白一点,Facade功能可以让类无需实例化而直接进行静态方式调用。

如果没有通过getFacadeClass方法显式指定要静态代理的类,可以在调用的时候进行动态绑定:

<?php
namespace app\facade;

use think\Facade;

class Test extends Facade
{
}
use app\facade\Test;
use think\Facade;

Facade::bind('app\facade\Test', 'app\common\Test');
echo Test::hello('thinkphp');

bind方法支持批量绑定,因此你可以在应用的公共函数文件中统一进行绑定操作,例如:

Facade::bind([
    'app\facade\Test' => 'app\common\Test',
    'app\facade\Info' => 'app\common\Info',
]);

核心Facade类库

系统给内置的常用类库定义了Facade类库,包括:

(动态)类库Facade类
think\Appthink\facade\App
think\Buildthink\facade\Build
think\Cachethink\facade\Cache
think\Configthink\facade\Config
think\Cookiethink\facade\Cookie
think\Debugthink\facade\Debug
think\Envthink\facade\Env
think\Hookthink\facade\Hook
think\Langthink\facade\Lang
think\Logthink\facade\Log
think\Middlewarethink\facade\Middleware
think\Requestthink\facade\Request
think\Responsethink\facade\Response
think\Routethink\facade\Route
think\Sessionthink\facade\Session
think\Urlthink\facade\Url
think\Validatethink\facade\Validate
think\Viewthink\facade\View

所以你无需进行实例化就可以很方便的进行方法调用,例如:

use think\facade\Cache;

Cache::set('name','value');
echo Cache::get('name');

think\Db类的实现本来就类似于Facade机制,所以不需要再进行静态代理就可以使用静态方法调用(确切的说Db类是没有方法的,都是调用的Query类的方法)。

在进行依赖注入的时候,请不要使用Facade类作为类型约束,而是建议使用原来的动态类,下面是错误的用法:

<?php
namespace app\index\controller;

use think\facade\App;

class Index
{
    public function index(App $app)
    {
    }
}

应当使用下面的方式:

<?php
namespace app\index\controller;

use think\App;

class Index
{
    public function index(App $app)
    {
    }
}

为了更加方便的使用系统类库,系统还给这些常用的核心类库的Facade类注册了类库别名,当进行静态调用的时候可以直接使用简化的别名进行调用。

别名类对应Facade类
Appthink\facade\App
Buildthink\facade\Build
Cachethink\facade\Cache
Configthink\facade\Config
Cookiethink\facade\Cookie
Dbthink\Db
Debugthink\facade\Debug
Envthink\facade\Env
Hookthink\facade\Hook
Langthink\facade\Lang
Logthink\facade\Log
Middlewarethink\facade\Middleware
Requestthink\facade\Request
Responsethink\facade\Response
Routethink\facade\Route
Sessionthink\facade\Session
Urlthink\facade\Url
Validatethink\facade\Validate
Viewthink\facade\View

因此前面的代码可以改成

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

Facade类定义了一个实例化的instance方法,如果你的类也有定义的话将会失效。