首頁  >  文章  >  php框架  >  在程式碼中取得到容器執行個體(Laravel)

在程式碼中取得到容器執行個體(Laravel)

藏色散人
藏色散人轉載
2021-08-06 09:35:101785瀏覽

本文由laravel教學專欄跟大家介紹怎麼在程式碼中取得到容器實例,希望對需要的朋友有幫助!

laravel容器實例在整個請求生命週期中都是唯一的,並且管理所有的服務元件實例。那麼有哪些方式能夠拿到laravel容器的實例呢?常用的有以下幾種方式:

1) 透過app這個help函數:

$app = app();

app這個輔助函數定義在

在程式碼中取得到容器執行個體(Laravel)

##文件裡面,這個檔案定義了很多help函數,並且會透過composer自動載入到專案中。所以,在參與http請求處理的任何程式碼位置都能夠存取其中的函數,例如app()。

2)透過App這個Facade

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

透過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 &#39;app&#39;;
    }
}

它的getFacadeAccessor回傳的就是一個字串“app”,這個app就是laravel容器自己綁定自己時用的名稱。

第二點:從上一點最後App這個Facade的源碼可以看出,App這個Facade的全類名其實是:Illuminate\Support\Facades\App,那為什麼我們在程式碼裡面能夠直接通過App這個簡短的名稱就能訪問到呢:

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

你看以上程式碼完全沒有用到use或完全限定的方式來使用Illuminate\Support\Facades\App。實際上App跟Illuminate\Support\Facades\App是完全等價的,只不過App比Illuminate\Support\Facades\App要簡短很多,而且不需要use,所以用起來方便,那麼它是怎麼實現的?這跟laravel容器配置的別名有關係,在config/app.php中,

有一節aliases專門用來設定一些類型的別名:

&#39;aliases&#39; => [
    &#39;App&#39; => Illuminate\Support\Facades\App::class,
    &#39;Artisan&#39; => Illuminate\Support\Facades\Artisan::class,
    &#39;Auth&#39; => Illuminate\Support\Facades\Auth::class,
    &#39;Blade&#39; => Illuminate\Support\Facades\Blade::class,
    &#39;Bus&#39; => Illuminate\Support\Facades\Bus::class,
    &#39;Cache&#39; => Illuminate\Support\Facades\Cache::class,
    &#39;Config&#39; => Illuminate\Support\Facades\Config::class,
    &#39;Cookie&#39; => Illuminate\Support\Facades\Cookie::class,
    &#39;Crypt&#39; => Illuminate\Support\Facades\Crypt::class,
    &#39;DB&#39; => Illuminate\Support\Facades\DB::class,
    &#39;Eloquent&#39; => Illuminate\Database\Eloquent\Model::class,
    &#39;Event&#39; => Illuminate\Support\Facades\Event::class,
    &#39;File&#39; => Illuminate\Support\Facades\File::class,
    &#39;Gate&#39; => Illuminate\Support\Facades\Gate::class,
    &#39;Hash&#39; => Illuminate\Support\Facades\Hash::class,
    &#39;Lang&#39; => Illuminate\Support\Facades\Lang::class,
    &#39;Log&#39; => Illuminate\Support\Facades\Log::class,
    &#39;Mail&#39; => Illuminate\Support\Facades\Mail::class,
    &#39;Notification&#39; => Illuminate\Support\Facades\Notification::class,
    &#39;Password&#39; => Illuminate\Support\Facades\Password::class,
    &#39;Queue&#39; => Illuminate\Support\Facades\Queue::class,
    &#39;Redirect&#39; => Illuminate\Support\Facades\Redirect::class,
    &#39;Redis&#39; => Illuminate\Support\Facades\Redis::class,
    &#39;Request&#39; => Illuminate\Support\Facades\Request::class,
    &#39;Response&#39; => Illuminate\Support\Facades\Response::class,
    &#39;Route&#39; => Illuminate\Support\Facades\Route::class,
    &#39;Schema&#39; => Illuminate\Support\Facades\Schema::class,
    &#39;Session&#39; => Illuminate\Support\Facades\Session::class,
    &#39;Storage&#39; => Illuminate\Support\Facades\Storage::class,
    &#39;URL&#39; => Illuminate\Support\Facades\URL::class,
    &#39;Validator&#39; => Illuminate\Support\Facades\Validator::class,
    &#39;View&#39; => 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(&#39;config&#39;)->get(&#39;app.aliases&#39;, []))->register();
    }
}

所以我們才能直接透過別名,取代完整的型別名做同樣的存取功能。如果你自己寫了一些類,名稱很長,在程式碼裡面用的特別多,也可以考慮配置到config/app.php別名裡面去,laravel會幫我們註冊。

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

服務提供者後面還會介紹,現在只是引入。因為服務提供者類別都是由laravel容器實例化的,這些類別都繼承自Illuminate\Support\ServiceProvider,它定義了一個實例屬性$app

在程式碼中取得到容器執行個體(Laravel)

laravel在實例化服務提供者的時候,會把laravel容器實例注入到這個$app上面。所以我們在服務提供者裡面,總是能透過$this->$app存取到laravel容器實例,而不需要再使用app()函數或是App Facade了。

更多laravel技術文章,請造訪laravel教學專欄!

以上是在程式碼中取得到容器執行個體(Laravel)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:杨子。如有侵權,請聯絡admin@php.cn刪除