服務(wù)提供者
服務(wù)提供者
服務(wù)提供者
簡介
服務(wù)提供者是所有 Laravel 應(yīng)用程序的引導(dǎo)中心。你的應(yīng)用程序,以及 通過服務(wù)器引導(dǎo)的 Laravel 核心服務(wù)都是通過服務(wù)提供器引導(dǎo)。
但是,「引導(dǎo)」是什么意思呢? 通常,我們的可以理解為注冊,比如注冊服務(wù)容器綁定,事件監(jiān)聽器,中間件,甚至是路由。服務(wù)提供者是配置應(yīng)用程序的中心。
當(dāng)你打開 Laravel 的 config/app.php
文件時,你會看到 providers
數(shù)組。數(shù)組中的內(nèi)容是應(yīng)用程序要加載的所有服務(wù)提供者的類。當(dāng)然,其中有很多 「延遲」 提供者,他們并不會在每次請求的時候都加載,只有他們的服務(wù)實際被需要時才會加載。
本篇你將會學(xué)到如何編寫自己的服務(wù)提供者,并將其注冊到你的 Laravel 應(yīng)用程序中
編寫服務(wù)提供者
所有的服務(wù)提供者都會繼承 Illuminate\Support\ServiceProvider
類。 大多服務(wù)提供者都包含一個 register
和一個 boot
方法。在 register
方法中, 你只需要將事物綁定到服務(wù)容器。而不要嘗試在 register
方法中注冊任何監(jiān)聽器,路由,或者其他任何功能
使用 Artisan 命令行工具,通過 make:provider
命令可以生成一個新的提供者:
php artisan make:provider RiakServiceProvider
注冊方法
如上所述,在 register
方法中,你只需要將服務(wù)綁定到服務(wù)容器中。而不要嘗試在 register
方法中注冊任何監(jiān)聽器,路由,或者其他任何功能。否則,你可能會意外地使用到尚未加載的服務(wù)提供者提供的服務(wù)。
讓我們來看一個基礎(chǔ)的服務(wù)提供者。在任何服務(wù)提供者方法中,你總是通過 $app
屬性來訪問服務(wù)容器:
<?php namespace App\Providers;use Riak\Connection; use Illuminate\Support\ServiceProvider; class RiakServiceProvider extends ServiceProvider{ /** * 在服務(wù)容器里注冊 * * @return void */ public function register() { $this->app->singleton(Connection::class, function ($app) { return new Connection(config('riak')); }); } }
這個服務(wù)容器只是定義了一個 register
方法,并且使用該這個方法在服務(wù)容器中定義了一個 Riak\Connection
接口。如果你不理解服務(wù)容器的工作原理,請查看其文檔。
bindings
和 singletons
的特性
如果你的服務(wù)提供器注冊了許多簡單的綁定,你可能想用 bindings
和 singletons
屬性替代手動注冊每個容器綁定。當(dāng)服務(wù)提供器被框架加載時,將自動檢查這些屬性并注冊相應(yīng)的綁定
<?php namespace App\Providers; use App\Contracts\ServerProvider; use App\Contracts\DowntimeNotifier; use Illuminate\Support\ServiceProvider; use App\Services\PingdomDowntimeNotifier; use App\Services\DigitalOceanServerProvider; class AppServiceProvider extends ServiceProvider{ /** * 設(shè)定所有的容器綁定的對應(yīng)關(guān)系 * * @var array */ public $bindings = [ ServerProvider::class => DigitalOceanServerProvider::class, ]; /** * 設(shè)定所有的單例模式容器綁定的對應(yīng)關(guān)系 * * @var array */ public $singletons = [ DowntimeNotifier::class => PingdomDowntimeNotifier::class, ]; }
引導(dǎo)方法
如果我們要在服務(wù)提供者中注冊一個 視圖合成器 該怎么做? 這就需要用到 boot
方法了。 該方法在所有服務(wù)提供者被注冊以后才會被調(diào)用, 這就是說我們可以在其中訪問框架已注冊的所有其它服務(wù):
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class ComposerServiceProvider extends ServiceProvider{ /** * 啟動所有的應(yīng)用服務(wù)。 * * @return void */ public function boot() { view()->composer('view', function () { // }); } }
啟動方法的依賴注入
你可以為服務(wù)提供者的 boot
方法設(shè)置類型提示。 服務(wù)容器 會自動注入你所需要的依賴:
use Illuminate\Contracts\Routing\ResponseFactory; public function boot(ResponseFactory $response){ $response->macro('caps', function ($value) { // }); }
注冊服務(wù)提供者
所有服務(wù)提供者都是通過配置文件 config/app.php
進(jìn)行注冊。該文件包含了一個列出所有服務(wù)提供者名字的 providers
數(shù)組,默認(rèn)情況下,其中列出了所有核心服務(wù)提供者,這些服務(wù)提供者啟動 Laravel 核心組件,比如郵件、隊列、緩存等等。
要注冊提供器,只需要將其添加到數(shù)組:
'providers' => [ // 其他服務(wù)提供者 App\Providers\ComposerServiceProvider::class,],
延遲提供者
如果你的服務(wù)提供者 只 在 服務(wù)容器 中注冊,可以選擇延遲加載該綁定直到注冊綁定的服務(wù)真的需要時再加載,延遲加載這樣的一個提供者將會提升應(yīng)用的性能,因為它不會在每次請求時都從文件系統(tǒng)加載。
Laravel 編譯并保存延遲服務(wù)提供者提供的所有服務(wù)的列表,以及其服務(wù)提供者類的名稱。因此,只有當(dāng)你在嘗試解析其中一項服務(wù)時,Laravel 才會加載服務(wù)提供者。
要延遲加載提供者,需要實現(xiàn) \Illuminate\Contracts\Support\DeferrableProvider
接口并置一個 provides
方法。這個 provides
方法返回該提供者注冊的服務(wù)容器綁定:
<?php namespace App\Providers; use Riak\Connection; use Illuminate\Support\ServiceProvider; use Illuminate\Contracts\Support\DeferrableProvider; class RiakServiceProvider extends ServiceProvider implements DeferrableProvider{ /** * 注冊服務(wù)提供者。 * * @return void */ public function register() { $this->app->singleton(Connection::class, function ($app) { return new Connection($app['config']['riak']); }); } /** * 獲取由提供者提供的服務(wù)。 * * @return array */ public function provides() { return [Connection::class]; } }