Laravel中Facade的加载过程与原理详解
前言
本文主要给大家介绍了关于Laravel中Facade加载过程与原理的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
简介
Facades(读音:/fəˈsäd/)为应用程序的服务容器中可用的类提供了一个「静态」接口。你不必use一大串的命名空间,也不用实例化对象,就能访问对象的具体方法。
useConfig; classTest { publicfunctionindex() { returnConfig::get('app.name'); } }
Facade的启动与注册
Facade的启动引导是在Illuminate\Foundation\Bootstrap\RegisterFacades中注册的。
publicfunctionbootstrap(Application$app) { Facade::clearResolvedInstances(); Facade::setFacadeApplication($app); AliasLoader::getInstance(array_merge( $app->make('config')->get('app.aliases',[]), $app->make(PackageManifest::class)->aliases() ))->register(); }
默认的别名配置是从app配置文件下的aliases读取的,PackageManifest是laravel5.5新增的包自动发现规则,这里我们暂时不考虑PackageManifest包提供的别名。
其中,array_merge返回如下格式的数组:
"App"=>"Illuminate\Support\Facades\App" "Artisan"=>"Illuminate\Support\Facades\Artisan" "Auth"=>"Illuminate\Support\Facades\Auth" "Blade"=>"Illuminate\Support\Facades\Blade" ...
上面代码将通过AliasLoader把所有的facade注册进自动加载。其核心就是php的spl_autoload_register。
/** *Prependtheloadmethodtotheauto-loaderstack. * *@returnvoid */ protectedfunctionregister() { if(!$this->registered){ spl_autoload_register([$this,'load'],true,true); $this->registered=true; } }
注册完成后,后续所有use的类都将通过load函数来完成类的自动加载。
注意:这里在定义spl_autoload_register时,最后面的参数传的是true。当该参数是true时,spl_autoload_register()会添加函数到队列之首,而不是队列尾部。(优先通过该函数来完成自动加载)
也就是说,
不管我们use的是具体存在的类(App\User)还是别名(Config),都将最先通过load函数来完成自动加载,当该函数返回false时,再由其他自动加载函数来完成自动加载(如composerpsr-4)。
在AliasLoader的load方法中,主要是用了class_alias函数来实现的别名自动加载。
publicfunctionload($alias) { if(isset($this->aliases[$alias])){ returnclass_alias($this->aliases[$alias],$alias); } }关于class_alias这里帖一个官方的列子:
classfoo{} class_alias('foo','bar'); $a=newfoo; $b=newbar; //theobjectsarethesame var_dump($a==$b,$a===$b);//true var_dump($ainstanceof$b);//false //theclassesarethesame var_dump($ainstanceoffoo);//true var_dump($ainstanceofbar);//true var_dump($binstanceoffoo);//true var_dump($binstanceofbar);//trueFacade的加载
当我们在使用Facade时,如:
实际上加载的是Illuminate\Support\Facades\Config类(因为我们已经注册了class_alias),相当于:
而所有的Facade都继承自Illuminate\Support\Facades\Facade类,在该基类中定义了一个__callStatic方法,已至于我们能够轻松地使用Facade(不用实列化)。
$method(...$args); }getFacadeRoot方法用于获取别名类的具体实列,我们知道,所有的Facade类都需要定义一个getFacadeAccessor方法。该方法可能的返回值有:
- String类型的字符串(如config,db)
- String类型的类字符串(如App\Service\SomeService)
- Object具体的实列化对象
- Closure闭包
如ConfigFacade的getFacadeAccessor方法如下:
protectedstaticfunctiongetFacadeAccessor() { return'config'; }
getFacadeRoot方法将根据getFacadeAccessor()的返回值,从容器从取出对应的实列对象。
publicstaticfunctiongetFacadeRoot() { $name=static::getFacadeAccessor(); if(is_object($name)){ return$name; } if(isset(static::$resolvedInstance[$name])){ returnstatic::$resolvedInstance[$name]; } returnstatic::$resolvedInstance[$name]=static::$app[$name]; }
由于APP容器中已经注册过config的实列
instance('config',$config=newRepository($items));
所以\Config::get('app.name','dafault)实际访问的是Repository实列的get('app.name','default')方法。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。