本文由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;不是一個合法的可執行的語句,而$app = app();卻是一個合法的可執行的語句,因為它後面有app(),表示函數呼叫。 App::basePath();也是一個合法的語句,它就是在呼叫類別的靜態方法。 再補充2點:第一點: Facade是laravel框架裡面比較特殊的一個特性,每個Facade都會與容器裡面的一個實例物件關聯,我們可以直接透過Facade類別靜態方法呼叫的形式來呼叫它關聯的實例物件的方法。例如App這個Facade,呼叫App::basePath()的時候,實際上相當於app()->basePath()。 這個底層機制也是依賴php語言的特性才能實現的,需要在每一個Facade裡面,設定一個靜態成員並關聯到一個服務的實例對象,當調用Facade類的靜態方法的時候,解析出呼叫的方法名,再去呼叫關聯的服務實例的同名方法,最後把結果回傳。 我認為理解Facade能起到什麼作用就夠了,不一定要深究到它底層去了解實現的細節,畢竟在實際的開發中,不用Facade,也完全不影響laravel框架的使用。另外在實際編碼中,要自訂一個Facade也非常容易,只要繼承laravel封裝的Facade基底類別即可:
<?php namespace ThirdProviders\CasServer\Facades; use Illuminate\Support\Facades\Facade; use ThirdProviders\CasServer\CasServerManager; class CasServer extends Facade { protected static function getFacadeAccessor() { return CasServerManager::class; } }實作Facade基底類別的getFacadeAccessor方法,laravel框架就知道這個Facade類別該與哪個服務實例關聯起來了。實際上這個getFacadeAccess方法,回傳的名稱就是後面要介紹的服務綁定名稱。在laravel容器裡面,一個服務實例,都會有一個固定的綁定名稱,透過這個名稱就能找到這個實例。所以為啥Facade類別只要回傳服務綁定名稱即可。 我們可以看看App這個Facade類別的程式碼:
<?php namespace Illuminate\Support\Facades; /** * @see \Illuminate\Foundation\Application */ 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的全類名其實是:Illuminate\Support\Facades\App,那為什麼我們在程式碼裡面能夠直接通過App這個簡短的名稱就能訪問到呢:
<?php Route::get('/', function () { dd(App::basePath()); return ''; });你看以上程式碼完全沒有用到use或完全限定的方式來使用Illuminate\Support\Facades\App。實際上App跟Illuminate\Support\Facades\App是完全等價的,只不過App比Illuminate\Support\Facades\App要簡短很多,而且不需要use,所以用起來方便,那麼它是怎麼實現的?這跟laravel容器配置的別名有關係,在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, '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\Database\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 ],然後在laravel框架處理請求過程中,會透過Illuminate\Foundation\Bootstrap\RegisterFacades這個類別來註冊這些別名到全域環境裡面:
<?php namespace Illuminate\Foundation\Bootstrap; use Illuminate\Support\Facades\Facade; use Illuminate\Foundation\AliasLoader; 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::clearResolvedInstances(); Facade::setFacadeApplication($app); AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register(); } }所以我們才能直接透過別名,取代完整的型別名做同樣的存取功能。如果你自己寫了一些類,名稱很長,在程式碼裡面用的特別多,也可以考慮配置到config/app.php別名裡面去,laravel會幫我們註冊。 3)另外一種方式拿到laravel容器實例就是在服務提供者裡面直接使用$this->app服務提供者後面還會介紹,現在只是引入。因為服務提供者類別都是由laravel容器實例化的,這些類別都繼承自Illuminate\Support\ServiceProvider,它定義了一個實例屬性$app laravel在實例化服務提供者的時候,會把laravel容器實例注入到這個$app上面。所以我們在服務提供者裡面,總是能透過$this->$app存取到laravel容器實例,而不需要再使用app()函數或是App Facade了。
更多laravel技術文章,請造訪laravel教學專欄!
以上是在程式碼中取得到容器執行個體(Laravel)的詳細內容。更多資訊請關注PHP中文網其他相關文章!