门面(Facade

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

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

下面是个示例 假如 定义了个appcommonTest类 里面有个hello动态方法。

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

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

$test = new appcommonTest;echo $test->hello('thinkphp'); // 输出 hello thinkphp

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

<?phpnamespace appfacade;use thinkFacade;class Test extends Facade{protected static function getFacadeClass(){return 'appcommonTest';
    }
}

只要这个类库继承thinkFacade 就可以使用静态方式调用动态类appcommonTest的动态方法 例如上面的代码就可以改成:

// 无需进行实例化 直接以静态方法方式调用helloecho appfacadeTest::hello('thinkphp');

结果也会输出 hello thinkphp

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

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

<?php
namespace appfacade;

use thinkFacade;class Test extends Facade{
}
use appfacadeTest;use thinkFacade;

Facade::bind('appfacadeTest', 'appcommonTest');echo Test::hello('thinkphp');

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

Facade::bind([
'appfacadeTest' => 'appcommonTest',
    'appfacadeInfo' => 'appcommonInfo',
]);

核心Facade类库

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

(动态)类库Facade类
thinkAppthinkfacadeApp
thinkBuildthinkfacadeBuild
thinkCachethinkfacadeCache
thinkConfigthinkfacadeConfig
thinkCookiethinkfacadeCookie
thinkDebugthinkfacadeDebug
thinkEnvthinkfacadeEnv
thinkHookthinkfacadeHook
thinkLangthinkfacadeLang
thinkLogthinkfacadeLog
thinkMiddlewarethinkfacadeMiddleware
thinkRequestthinkfacadeRequest
thinkResponsethinkfacadeResponse
thinkRoutethinkfacadeRoute
thinkessionthinkfacadeession
thinkUrlthinkfacadeUrl
thinkValidatethinkfacadeValidate
thinkViewthinkfacadeView

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

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

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

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

<?phpnamespace appindexcontroller;use thinkfacadeApp;class Index{public function index(App $app){
    }
}

应当使用下面的方式:

<?phpnamespace appindexcontroller;use thinkApp;class Index{public function index(App $app){
    }
}

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

别名类对应Facade类
AppthinkfacadeApp
BuildthinkfacadeBuild
CachethinkfacadeCache
ConfigthinkfacadeConfig
CookiethinkfacadeCookie
DbthinkDb
DebugthinkfacadeDebug
EnvthinkfacadeEnv
HookthinkfacadeHook
LangthinkfacadeLang
LogthinkfacadeLog
MiddlewarethinkfacadeMiddleware
RequestthinkfacadeRequest
ResponsethinkfacadeResponse
RoutethinkfacadeRoute
Sessionthinkfacadeession
UrlthinkfacadeUrl
ValidatethinkfacadeValidate
ViewthinkfacadeView

因此前面的代码可以改成

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

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