上次说了provider,那么这次来说说facade
首先是启动的源头,从laravel的kernel类中的$bootstrappers 数组,我们可以看到它的一些系统引导方法,其中的RegisterFacades便是用来注册facade门面类的了。
protected $bootstrappers = [
\\Illuminate\\Foundation\\Bootstrap\\LoadEnvironmentVariables::class,
\\Illuminate\\Foundation\\Bootstrap\\LoadConfiguration::class,
\\Illuminate\\Foundation\\Bootstrap\\HandleExceptions::class,
\\Illuminate\\Foundation\\Bootstrap\\RegisterFacades::class,
\\Illuminate\\Foundation\\Bootstrap\\RegisterProviders::class,
\\Illuminate\\Foundation\\Bootstrap\\BootProviders::class,
];
同样是有一个register类,通过这个类进行别名等注册操作
namespace Illuminate\\Foundation\\Bootstrap; use Illuminate\\Foundation\\AliasLoader; use Illuminate\\Support\\Facades\\Facade; use Illuminate\\Foundation\\PackageManifest; use Illuminate\\Contracts\\Foundation\\Application; class RegisterFacades { /** * Bootstrap the given application. * * @param \\Illuminate\\Contracts\\Foundation\\Application $app * @return void */ public function bootstrap(Application $app) { //清除facade所有已绑定实例 Facade::clearResolvedInstances(); //将app存入对象 Facade::setFacadeApplication($app); //将这些别名数组通过构造函数存入对象中 AliasLoader::getInstance(array_merge( //通过Illuminate\\Config\\Repository获取config/app.php中的aliases数组 $app->make('config')->get('app.aliases', []), //还记得最开始的博文中提到的那个包清单吗,这里也从中获取了它的aliases $app->make(PackageManifest::class)->aliases() //通过spl_autoload_register函数注册另一种自动加载函数 ))->register(); } }
public static function getInstance(array $aliases = [])
{
//注册时的实例是空的,会通过构造方法把刚刚传入的别名数组存入对象
if (is_null(static::$instance)) {
return static::$instance = new static($aliases);
}
$aliases = array_merge(static::$instance->getAliases(), $aliases);
static::$instance->setAliases($aliases);
return static::$instance;
}
private function __construct($aliases)
{
$this->aliases = $aliases;
}
public function register()
{
if (! $this->registered) {
$this->prependToLoaderStack();
$this->registered = true;
}
}
/**
* Prepend the load method to the auto-loader stack.
*
* @return void
*/
protected function prependToLoaderStack()
{
//最后通过自动加载函数将本对象中的load方法放入自动加载队列的前端,在我们通过类名调用方法时,会触发自动加载函数队列,会优先触发这个函数,查找到对应文件的路径然后加载相应文件
spl_autoload_register([$this, 'load'], true, true);
}
public function load($alias)
{
//若传入的命名空间不为当前facade数组内才会通过这个方法加载
if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
$this->loadFacade($alias);
return true;
}
//否则直接返回其别名
if (isset($this->aliases[$alias])) {
return class_alias($this->aliases[$alias], $alias);
}
}
/**
* Load a real-time facade for the given alias.
*
* @param string $alias
* @return void
*/
protected function loadFacade($alias)
{
require $this->ensureFacadeExists($alias);
}
/**
* Ensure that the given alias has an existing real-time facade class.
*
* @param string $alias
* @return string
*/
protected function ensureFacadeExists($alias)
{
//从缓存中返回路径
if (file_exists($path = storage_path(' work/cache/facade-'.sha1($alias).'.php'))) {
return $path;
}
file_put_contents($path, $this->formatFacadeStub(
$alias, file_get_contents(__DIR__.'/stubs/facade.stub')
));
return $path;
}
由于laravel中composer的执行过程过于繁琐,这里就不做深究了。原理是一样的,通过别名找到命名空间的类名,再由composer的类名与文件路径映射关系,自动加载函数找到相应文件加载进来。
那么我们来自定义一个门面类试一下
1、新建一个facade类,这里返回的test是上一篇博客中定义的对象
namespace App\\Facades; use Illuminate\\Support\\Facades\\Facade; class Test extends Facade { protected static function getFacadeAccessor() { return 'App\\Contracts\\Test'; } }
2、将它添加到config/app.php的aliases别名数组中
'aliases' => [ 'App' => Illuminate\\Support\\Facades\\App::class, 'Artisan' => Illuminate\\Support\\Facades\\Artisan::class, 'Auth' => Illuminate\\Support\\Facades\\Auth::class, 'Blade' => Illuminate\\Support\\Facades\\Blade::class, 'Broadcast' => Illuminate\\Support\\Facades\\Broadcast::class, 'Bus' => Illuminate\\Support\\Facades\\Bus::class, 'Cache' => Illuminate\\Support\\Facades\\Cache::class, 'Config' => Illuminate\\Support\\Facades\\Config::class, 'Cookie' => Illuminate\\Support\\Facades\\Cookie::class, 'Crypt' => Illuminate\\Support\\Facades\\Crypt::class, 'DB' => Illuminate\\Support\\Facades\\DB::class, 'Eloquent' => Illuminate\\Data \\Eloquent\\Model::class, 'Event' => Illuminate\\Support\\Facades\\Event::class, 'File' => Illuminate\\Support\\Facades\\File::class, 'Gate' => Illuminate\\Support\\Facades\\Gate::class, 'Hash' => Illuminate\\Support\\Facades\\Hash::class, 'Lang' => Illuminate\\Support\\Facades\\Lang::class, 'Log' => Illuminate\\Support\\Facades\\Log::class, 'Mail' => Illuminate\\Support\\Facades\\Mail::class, 'Notification' => Illuminate\\Support\\Facades\\Notification::class, 'Password' => Illuminate\\Support\\Facades\\Password::class, 'Queue' => Illuminate\\Support\\Facades\\Queue::class, 'Redirect' => Illuminate\\Support\\Facades\\Redirect::class, 'Redis' => Illuminate\\Support\\Facades\\Redis::class, 'Request' => Illuminate\\Support\\Facades\\Request::class, 'Response' => Illuminate\\Support\\Facades\\Response::class, 'Route' => Illuminate\\Support\\Facades\\Route::class, 'Schema' => Illuminate\\Support\\Facades\\Schema::class, 'Session' => Illuminate\\Support\\Facades\\Session::class, 'Storage' => Illuminate\\Support\\Facades\\Storage::class, 'URL' => Illuminate\\Support\\Facades\\URL::class, 'Validator' => Illuminate\\Support\\Facades\\Validator::class, 'View' => Illuminate\\Support\\Facades\\View::class, //刚刚新建的facades 'Test' => \\App\\Facades\\Test::class, ],
3、在路由文件中调用它
Route::any('/index', function (){
Test::doing();
});
我们会发现,即使我们没有通过app对象进行make也没有任何命名空间的引入,它就这样被调用了。
如果是在类中调用,那么就要麻烦一些了,需要ues这个别名,注意这一点
namespace App\\Http\\Controllers; use Illuminate\\Http\\Request; //use App\\Contracts\\Test; //注意这里只引入了别名,由于命名空间冲突,所以我注释了其他部分 use Test; class IndexController extends Controller { // public function __construct(Test $test) // { // $this->test = $test; // } public function index(Test $test) { Test::doing(); // app()->make('App\\Contracts\\Test')->doing(); // echo '<br>'; // // //只有通过构造方法进行自动加载依赖的方式才能触发契约的when绑定 // $this->test->doing(); // // echo '<br>'; // //因为laravel中的上下文绑定只能具体到类,所以这里的$test实例依然为普通绑定 // $test->doing(); } }
通过这个demo的实践,facade还是比较简单的。
继续阅读与本文标签相同的文章
上一篇 :
Vue递归实现树形菜单方法实例
-
Excel表格中的柱状图上如何添加平均线?
2026-05-19栏目: 教程
-
嘉益仕MES教你如何搞定精细化管理
2026-05-19栏目: 教程
-
Kotlin的分享
2026-05-19栏目: 教程
-
腾讯发布智慧社区标准化解决方案,目前已覆盖超过7000个小区
2026-05-19栏目: 教程
-
四方科技:冷链装备龙头 罐箱业务全球领先
2026-05-19栏目: 教程
