在代碼中獲取到容器實(shí)例(Laravel)

本文由laravel教程欄目給大家介紹怎么在代碼中獲取到容器實(shí)例,希望對(duì)需要的朋友有所幫助!

laravel容器實(shí)例在整個(gè)請(qǐng)求生命周期中都是唯一的,且管理著所有的服務(wù)組件實(shí)例。那么有哪些方式能夠拿到laravel容器的實(shí)例呢?常用的有以下幾種方式:

1) 通過(guò)app這個(gè)help函數(shù):

$app?=?app();

app這個(gè)輔助函數(shù)定義在

在代碼中獲取到容器實(shí)例(Laravel)

文件里面,這個(gè)文件定義了很多help函數(shù),并且會(huì)通過(guò)composer自動(dòng)加載到項(xiàng)目中。所以,在參與http請(qǐng)求處理的任何代碼位置都能夠訪問(wèn)其中的函數(shù),比如app()。

2)通過(guò)App這個(gè)Facade

<?php Route::get(&#39;/&#39;, function () {     dd(App::basePath());     return &#39;&#39;; });

通過(guò)App這個(gè)Facade拿容器實(shí)例的方式,跟上面不同的是,不能把App先賦給一個(gè)變量,然后通過(guò)變量來(lái)調(diào)用容器的方法。這是因?yàn)锳pp相當(dāng)于只是一個(gè)類(lèi)名,我們不能把一個(gè)類(lèi)名復(fù)制一個(gè)變量。$app = App;不是一個(gè)合法的可執(zhí)行的語(yǔ)句,而$app = app();卻是一個(gè)合法的可執(zhí)行的語(yǔ)句,因?yàn)樗竺嬗衋pp(),表示函數(shù)調(diào)用。App::basePath();也是一個(gè)合法的語(yǔ)句,它就是在調(diào)用類(lèi)的靜態(tài)方法。

再補(bǔ)充2點(diǎn):

第一點(diǎn): Facade是laravel框架里面比較特殊的一個(gè)特性,每個(gè)Facade都會(huì)與容器里面的一個(gè)實(shí)例對(duì)象關(guān)聯(lián),我們可以直接通過(guò)Facade類(lèi)靜態(tài)方法調(diào)用的形式來(lái)調(diào)用它關(guān)聯(lián)的實(shí)例對(duì)象的方法。比如App這個(gè)Facade,調(diào)用App::basePath()的時(shí)候,實(shí)際相當(dāng)于app()->basePath()。

這個(gè)底層機(jī)制也是依賴于php語(yǔ)言的特性才能實(shí)現(xiàn)的,需要在每一個(gè)Facade里面,設(shè)定一個(gè)靜態(tài)成員并關(guān)聯(lián)到一個(gè)服務(wù)的實(shí)例對(duì)象,當(dāng)調(diào)用Facade類(lèi)的靜態(tài)方法的時(shí)候,解析出調(diào)用的方法名,再去調(diào)用關(guān)聯(lián)的服務(wù)實(shí)例的同名方法,最后把結(jié)果返回。

我認(rèn)為理解Facade能起到什么作用就夠了,不一定要深究到它底層去了解實(shí)現(xiàn)的細(xì)節(jié),畢竟在實(shí)際的開(kāi)發(fā)中,不用Facade,也完全不影響laravel框架的使用。另外在實(shí)際編碼中,要自定義一個(gè)Facade也非常容易,只要繼承l(wèi)aravel封裝的Facade基類(lèi)即可:

<?php namespace ThirdProvidersCasServerFacades; use IlluminateSupportFacadesFacade; use ThirdProvidersCasServerCasServerManager; class CasServer extends Facade {     protected static function getFacadeAccessor()     {         return CasServerManager::class;     } }

實(shí)現(xiàn)Facade基類(lèi)的getFacadeAccessor方法,laravel框架就知道這個(gè)Facade類(lèi)該與哪個(gè)服務(wù)實(shí)例關(guān)聯(lián)起來(lái)了。實(shí)際上這個(gè)getFacadeAccess方法,返回的名稱(chēng)就是后面要介紹的服務(wù)綁定名稱(chēng)。在laravel容器里面,一個(gè)服務(wù)實(shí)例,都會(huì)有一個(gè)固定的綁定名稱(chēng),通過(guò)這個(gè)名稱(chēng)就能找到這個(gè)實(shí)例。所以為啥Facade類(lèi)只要返回服務(wù)綁定名稱(chēng)即可。

我們可以看看App這個(gè)Facade類(lèi)的代碼:

<?php namespace IlluminateSupportFacades; /**  * @see IlluminateFoundationApplication  */ class App extends Facade {     /**      * Get the registered name of the component.      *      * @return string      */     protected static function getFacadeAccessor()     {         return &#39;app&#39;;     } }

它的getFacadeAccessor返回的就是一個(gè)字符串“app”,這個(gè)app就是laravel容器自己綁定自己時(shí)用的名稱(chēng)。

第二點(diǎn):從上一點(diǎn)最后App這個(gè)Facade的源碼可以看出,App這個(gè)Facade的全類(lèi)名其實(shí)是:IlluminateSupportFacadesApp,那為什么我們?cè)诖a里面能夠直接通過(guò)App這個(gè)簡(jiǎn)短的名稱(chēng)就能訪問(wèn)到呢:

<?php Route::get(&#39;/&#39;, function () {     dd(App::basePath());     return &#39;&#39;; });

你看以上代碼完全沒(méi)有用到use或者完全限定的方式來(lái)使用IlluminateSupportFacadesApp。實(shí)際上App跟IlluminateSupportFacadesApp是完全等價(jià)的,只不過(guò)App比IlluminateSupportFacadesApp要簡(jiǎn)短很多,而且不需要use,所以用起來(lái)方便,那么它是怎么實(shí)現(xiàn)的?這跟laravel容器配置的別名有關(guān)系,在config/app.php中,

有一節(jié)aliases專(zhuān)門(mén)用來(lái)配置一些類(lèi)型的別名:

'aliases'?=&gt;?[ ????'App'?=&gt;?IlluminateSupportFacadesApp::class, ????'Artisan'?=&gt;?IlluminateSupportFacadesArtisan::class, ????'Auth'?=&gt;?IlluminateSupportFacadesAuth::class, ????'Blade'?=&gt;?IlluminateSupportFacadesBlade::class, ????'Bus'?=&gt;?IlluminateSupportFacadesBus::class, ????'Cache'?=&gt;?IlluminateSupportFacadesCache::class, ????'Config'?=&gt;?IlluminateSupportFacadesConfig::class, ????'Cookie'?=&gt;?IlluminateSupportFacadesCookie::class, ????'Crypt'?=&gt;?IlluminateSupportFacadesCrypt::class, ????'DB'?=&gt;?IlluminateSupportFacadesDB::class, ????'Eloquent'?=&gt;?IlluminateDatabaseEloquentModel::class, ????'Event'?=&gt;?IlluminateSupportFacadesEvent::class, ????'File'?=&gt;?IlluminateSupportFacadesFile::class, ????'Gate'?=&gt;?IlluminateSupportFacadesGate::class, ????'Hash'?=&gt;?IlluminateSupportFacadesHash::class, ????'Lang'?=&gt;?IlluminateSupportFacadesLang::class, ????'Log'?=&gt;?IlluminateSupportFacadesLog::class, ????'Mail'?=&gt;?IlluminateSupportFacadesMail::class, ????'Notification'?=&gt;?IlluminateSupportFacadesNotification::class, ????'Password'?=&gt;?IlluminateSupportFacadesPassword::class, ????'Queue'?=&gt;?IlluminateSupportFacadesQueue::class, ????'Redirect'?=&gt;?IlluminateSupportFacadesRedirect::class, ????'Redis'?=&gt;?IlluminateSupportFacadesRedis::class, ????'Request'?=&gt;?IlluminateSupportFacadesRequest::class, ????'Response'?=&gt;?IlluminateSupportFacadesResponse::class, ????'Route'?=&gt;?IlluminateSupportFacadesRoute::class, ????'Schema'?=&gt;?IlluminateSupportFacadesSchema::class, ????'Session'?=&gt;?IlluminateSupportFacadesSession::class, ????'Storage'?=&gt;?IlluminateSupportFacadesStorage::class, ????'URL'?=&gt;?IlluminateSupportFacadesURL::class, ????'Validator'?=&gt;?IlluminateSupportFacadesValidator::class, ????'View'?=&gt;?IlluminateSupportFacadesView::class ],

然后在laravel框架處理請(qǐng)求過(guò)程中,會(huì)通過(guò)IlluminateFoundationBootstrapRegisterFacades這個(gè)類(lèi)來(lái)注冊(cè)這些別名到全局環(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')-&gt;get('app.aliases',?[]))-&gt;register(); ????} }

所以我們才能直接通過(guò)別名,代替完整的類(lèi)型名做同樣的訪問(wèn)功能。如果你自己寫(xiě)了一些類(lèi),名稱(chēng)很長(zhǎng),并且在代碼里面用的特別多,也可以考慮配置到config/app.php別名里面去,laravel會(huì)幫我們注冊(cè)。

3)另外一種方式拿到laravel容器實(shí)例就是在服務(wù)提供者里面直接使用$this->app

服務(wù)提供者后面還會(huì)介紹,現(xiàn)在只是引入。因?yàn)榉?wù)提供者類(lèi)都是由laravel容器實(shí)例化的,這些類(lèi)都繼承自IlluminateSupportServiceProvider,它定義了一個(gè)實(shí)例屬性$app

在代碼中獲取到容器實(shí)例(Laravel)

laravel在實(shí)例化服務(wù)提供者的時(shí)候,會(huì)把laravel容器實(shí)例注入到這個(gè)$app上面。所以我們?cè)诜?wù)提供者里面,始終能通過(guò)$this->$app訪問(wèn)到laravel容器實(shí)例,而不需要再使用app()函數(shù)或者App Facade了。

更多l(xiāng)aravel技術(shù)文章,請(qǐng)?jiān)L問(wèn)laravel欄目!

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊5 分享