Laravel Facade的加载过程及原理
Facades(讀音:/f??s?d/ )為應(yīng)用程序的?服務(wù)容器?中可用的類提供了一個「靜態(tài)」接口。你不必?use?一大串的命名空間,也不用實例化對象,就能訪問對象的具體方法。
use Config;class Test {public function index(){return Config::get('app.name');} }Facade 的啟動與注冊
Facade 的啟動引導(dǎo)是在?Illuminate\Foundation\Bootstrap\RegisterFacades?中注冊的。
public function bootstrap(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?是?laravel 5.5?新增的?包自動發(fā)現(xiàn)規(guī)則,這里我們暫時不考慮?PackageManifest?包提供的別名。
其中,array_merge?返回如下格式的數(shù)組:
"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。
/*** Prepend the load method to the auto-loader stack.** @return void*/protected function register(){if (! $this->registered) {spl_autoload_register([$this, 'load'], true, true);$this->registered = true;}}注冊完成后,后續(xù)所有?use?的類都將通過?load?函數(shù)來完成類的自動加載。
注意,這里在定義?spl_autoload_register?時,最后面的參數(shù)傳的是?true。當該參數(shù)是?true?時,spl_autoload_register()?會添加函數(shù)到隊列之首,而不是隊列尾部。(優(yōu)先通過該函數(shù)來完成自動加載)
也就是說,
<?phpuse Config; use App\User;class Test {public function index(){Config::get('app.name');new User();} }不管我們?use?的是具體存在的類(App\User)還是別名?(Config),都將最先通過?load?函數(shù)來完成自動加載,當該函數(shù)返回?false?時,再由其他自動加載函數(shù)來完成自動加載(如?composer psr-4)。
在?AliasLoader?的?load?方法中,主要是用了?class_alias?函數(shù)來實現(xiàn)的別名自動加載。
public function load($alias) {if (isset($this->aliases[$alias])) {return class_alias($this->aliases[$alias], $alias);} }關(guān)于?class_alias?這里帖一個官方的列子:
class foo { }class_alias('foo', 'bar');$a = new foo; $b = new bar;// the objects are the same var_dump($a == $b, $a === $b); //true var_dump($a instanceof $b); //false// the classes are the same var_dump($a instanceof foo); //true var_dump($a instanceof bar); //truevar_dump($b instanceof foo); //true var_dump($b instanceof bar); //trueFacade 的加載
當我們在使用?Facade?時,如:
<?phpuse Config;class Test {public function index(){Config::get('app.name');} }實際上加載的是?Illuminate\Support\Facades\Config?類(因為我們已經(jīng)注冊了?class_alias),相當于:
<?phpuse Illuminate\Support\Facades\Config;class Test {public function index(){Config::get('app.name');} }而所有的?Facade?都繼承自?Illuminate\Support\Facades\Facade?類,在該基類中定義了一個?__callStatic?方法,已至于我們能夠輕松地使用?Facade(不用實列化)。
<?phppublic static function __callStatic($method, $args) {$instance = static::getFacadeRoot();if (! $instance) {throw new RuntimeException('A facade root has not been set.');}return $instance->$method(...$args); }getFacadeRoot?方法用于獲取別名類的具體實列,我們知道,所有的?Facade?類都需要定義一個?getFacadeAccessor?方法。該方法可能的返回值有:
如?Config Facade?的?getFacadeAccessor?方法如下:
protected static function getFacadeAccessor() {return 'config'; }getFacadeRoot?方法將根據(jù)?getFacadeAccessor()?的返回值,從容器從取出對應(yīng)的實列對象。
public static function getFacadeRoot() {$name = static::getFacadeAccessor();if (is_object($name)) {return $name;}if (isset(static::$resolvedInstance[$name])) {return static::$resolvedInstance[$name];}return static::$resolvedInstance[$name] = static::$app[$name]; }由于 APP 容器中已經(jīng)注冊過?config?的實列
<?php //Illuminate\Foundation\Bootstrap/LoadConfiguration$app->instance('config', $config = new Repository($items));所以?\Config::get('app.name', 'dafault)?實際訪問的是?Repository?實列的?get('app.name', 'default')?方法。
參考文獻:
https://segmentfault.com/a/1190000011274118
總結(jié)
以上是生活随笔為你收集整理的Laravel Facade的加载过程及原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 力扣刷题-前k个高频元素
- 下一篇: TikTok推出多语种字幕和翻译工具