本文由laravel教程欄目給大家介紹怎么在代碼中獲取到容器實例,希望對需要的朋友有所幫助!
laravel容器實例在整個請求生命周期中都是唯一的,且管理著所有的服務組件實例。那么有哪些方式能夠拿到laravel容器的實例呢?常用的有以下幾種方式:
1) 通過app這個help函數:
$app = app();
app這個輔助函數定義在
文件里面,這個文件定義了很多help函數,并且會通過composer自動加載到項目中。所以,在參與http請求處理的任何代碼位置都能夠訪問其中的函數,比如app()。
2)通過App這個Facade
<?php Route::get('/', function () { dd(App::basePath()); return ''; });
通過App這個Facade拿容器實例的方式,跟上面不同的是,不能把App先賦給一個變量,然后通過變量來調用容器的方法。這是因為App相當于只是一個類名,我們不能把一個類名復制一個變量。$app = App;不是一個合法的可執(zhí)行的語句,而$app = app();卻是一個合法的可執(zhí)行的語句,因為它后面有app(),表示函數調用。App::basePath();也是一個合法的語句,它就是在調用類的靜態(tài)方法。
再補充2點:
第一點: Facade是laravel框架里面比較特殊的一個特性,每個Facade都會與容器里面的一個實例對象關聯,我們可以直接通過Facade類靜態(tài)方法調用的形式來調用它關聯的實例對象的方法。比如App這個Facade,調用App::basePath()的時候,實際相當于app()->basePath()。
這個底層機制也是依賴于php語言的特性才能實現的,需要在每一個Facade里面,設定一個靜態(tài)成員并關聯到一個服務的實例對象,當調用Facade類的靜態(tài)方法的時候,解析出調用的方法名,再去調用關聯的服務實例的同名方法,最后把結果返回。
我認為理解Facade能起到什么作用就夠了,不一定要深究到它底層去了解實現的細節(jié),畢竟在實際的開發(fā)中,不用Facade,也完全不影響laravel框架的使用。另外在實際編碼中,要自定義一個Facade也非常容易,只要繼承l(wèi)aravel封裝的Facade基類即可:
<?php namespace ThirdProvidersCasServerFacades; use IlluminateSupportFacadesFacade; use ThirdProvidersCasServerCasServerManager; class CasServer extends Facade { protected static function getFacadeAccessor() { return CasServerManager::class; } }
實現Facade基類的getFacadeAccessor方法,laravel框架就知道這個Facade類該與哪個服務實例關聯起來了。實際上這個getFacadeAccess方法,返回的名稱就是后面要介紹的服務綁定名稱。在laravel容器里面,一個服務實例,都會有一個固定的綁定名稱,通過這個名稱就能找到這個實例。所以為啥Facade類只要返回服務綁定名稱即可。
我們可以看看App這個Facade類的代碼:
<?php namespace IlluminateSupportFacades; /** * @see IlluminateFoundationApplication */ class App extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'app'; } }
它的getFacadeAccessor返回的就是一個字符串“app”,這個app就是laravel容器自己綁定自己時用的名稱。
第二點:從上一點最后App這個Facade的源碼可以看出,App這個Facade的全類名其實是:IlluminateSupportFacadesApp,那為什么我們在代碼里面能夠直接通過App這個簡短的名稱就能訪問到呢:
<?php Route::get('/', function () { dd(App::basePath()); return ''; });
你看以上代碼完全沒有用到use或者完全限定的方式來使用IlluminateSupportFacadesApp。實際上App跟IlluminateSupportFacadesApp是完全等價的,只不過App比IlluminateSupportFacadesApp要簡短很多,而且不需要use,所以用起來方便,那么它是怎么實現的?這跟laravel容器配置的別名有關系,在config/app.php中,
有一節(jié)aliases專門用來配置一些類型的別名:
'aliases' => [ 'App' => IlluminateSupportFacadesApp::class, 'Artisan' => IlluminateSupportFacadesArtisan::class, 'Auth' => IlluminateSupportFacadesAuth::class, 'Blade' => IlluminateSupportFacadesBlade::class, 'Bus' => IlluminateSupportFacadesBus::class, 'Cache' => IlluminateSupportFacadesCache::class, 'Config' => IlluminateSupportFacadesConfig::class, 'Cookie' => IlluminateSupportFacadesCookie::class, 'Crypt' => IlluminateSupportFacadesCrypt::class, 'DB' => IlluminateSupportFacadesDB::class, 'Eloquent' => IlluminateDatabaseEloquentModel::class, 'Event' => IlluminateSupportFacadesEvent::class, 'File' => IlluminateSupportFacadesFile::class, 'Gate' => IlluminateSupportFacadesGate::class, 'Hash' => IlluminateSupportFacadesHash::class, 'Lang' => IlluminateSupportFacadesLang::class, 'Log' => IlluminateSupportFacadesLog::class, 'Mail' => IlluminateSupportFacadesMail::class, 'Notification' => IlluminateSupportFacadesNotification::class, 'Password' => IlluminateSupportFacadesPassword::class, 'Queue' => IlluminateSupportFacadesQueue::class, 'Redirect' => IlluminateSupportFacadesRedirect::class, 'Redis' => IlluminateSupportFacadesRedis::class, 'Request' => IlluminateSupportFacadesRequest::class, 'Response' => IlluminateSupportFacadesResponse::class, 'Route' => IlluminateSupportFacadesRoute::class, 'Schema' => IlluminateSupportFacadesSchema::class, 'Session' => IlluminateSupportFacadesSession::class, 'Storage' => IlluminateSupportFacadesStorage::class, 'URL' => IlluminateSupportFacadesURL::class, 'Validator' => IlluminateSupportFacadesValidator::class, 'View' => IlluminateSupportFacadesView::class ],
然后在laravel框架處理請求過程中,會通過IlluminateFoundationBootstrapRegisterFacades這個類來注冊這些別名到全局環(huán)境里面:
<?php namespace IlluminateFoundationBootstrap; use IlluminateSupportFacadesFacade; use IlluminateFoundationAliasLoader; use IlluminateContractsFoundationApplication; class RegisterFacades { /** * Bootstrap the given application. * * @param IlluminateContractsFoundationApplication $app * @return void */ public function bootstrap(Application $app) { Facade::clearResolvedInstances(); Facade::setFacadeApplication($app); AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register(); } }
所以我們才能直接通過別名,代替完整的類型名做同樣的訪問功能。如果你自己寫了一些類,名稱很長,并且在代碼里面用的特別多,也可以考慮配置到config/app.php別名里面去,laravel會幫我們注冊。
3)另外一種方式拿到laravel容器實例就是在服務提供者里面直接使用$this->app
服務提供者后面還會介紹,現在只是引入。因為服務提供者類都是由laravel容器實例化的,這些類都繼承自IlluminateSupportServiceProvider,它定義了一個實例屬性$app
laravel在實例化服務提供者的時候,會把laravel容器實例注入到這個$app上面。所以我們在服務提供者里面,始終能通過$this->$app訪問到laravel容器實例,而不需要再使用app()函數或者App Facade了。