【Laravel】 サービスプロバイダを理解して作る
サービスプロバイダは、その名の通りサービスを提供するものです。
サービスプロバイダとは
Laravelから最初に入っているサービスプロバイダがそのまま例になります。
例えば、EventServiceProvider
は、イベントを発行したら紐付けたクラスのインスタンスを生成してイベントを投げる、という機能を提供しています。
RouteServiceProvider
は、ルーティングにおいて特定のグループに特定のミドルウェアを付ける、スロットリングを行うなどの機能を提供しています。
そういった、バックエンドで開発者向けに機能を提供するのがサービスプロバイダです。Laravelでは、初期化時にどんな風に設定するかがしばしば書かれ、サービスコンテナを利用します。
つまり、初期化時に何かしらの設定を行い、実際に動作する際にサービスコンテナを利用して機能を使う、といったときに役立つことが多いと思います。
サービスコンテナの知識がある方がスムーズに理解できます。
サービスプロバイダを作る
早速サービスプロバイダを作ってみましょう。
registerとboot
サービスコンテナでは、register
とboot
メソッドの2つが主役です。register
ではサービスコンテナへの登録のみを行い、boot
ではそのサービスプロバイダ固有の処理を行います。
register
で登録以外の処理を行おうとしても、その時点ではまだ利用できない機能が多くあるため、動作しない可能性があるので注意が必要です。
クラス作成と登録
クラスを作るには、artisan
を使用するのが手っ取り早いです。
php artisan make:provider EncryptServiceProvider
作成したら、そのサービスプロバイダを利用できるように登録する必要があります。登録するには、config/app.php
のproviders
に記述します。
use Illuminate\Support\Facades\Facade; return [ // ... 'providers' => [ // ... App\Providers\EncryptServiceProvider::class, ] ]
定義しても、そのままでは反映されません。php artisan optimize
してキャッシュをクリアする必要があります。
registerを実装
register
では、サービスコンテナに登録する処理を記述します。
public function register() { $this->app->bind('encrypt.aes256', function ($app, $context) { Log::debug($context['text']); return "hoge"; }); }
バインドとシングルトンの定義はregister
に記述する必要はなく、$bindings
と$singletons
に配列で並べることもできます。(無名関数は並べられません)
class EncryptServiceProvider extends ServiceProvider { // $this->app->bind の代わり public $bindings = [ IFooService::class => FugaService::class,, 'abcde' => HigeService::class, // ... ]; // $this->app->singleton の代わり public $singletons = [ HogeService::class => HogeService::class, // ... ]; // ... }
bootを定義
boot
では、他のサービスプロバイダで登録完了後に呼ばれます。そのため、様々な処理を行うことができます。
また、boot
の仮引数にタイプヒントを付けることで、サービスコンテナが適切なオブジェクトを注入してくれます。
public function boot(HogeService $hoge) { $hoge->outputLog(); }
遅延読み込み
もしサービスプロバイダがサービスコンテナへの登録のみを行う場合、実際に利用しない限りはそのサービスプロバイダをロードする必要は無いはずです。
その場合、DeferrableProvider
をimplement
し、provides
を作成して何を要求されたらサービスをロードするかを書きます。
namespace App\Providers; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; class EncryptServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register services. * * @return void */ public function register() { $this->app->bind('encrypt.aes256', function ($app, $context) { Log::debug($context['text']); return "hoge"; }); } public function provides() { return ['encrypt.aes256']; } }
遅延読み込みできているかは、register
内でLog::debug
でログを出すなどをすると判別できます。
php artisan optimize
しても遅延読み込みが反映されない場合、php artisan clear-compiled
やphp artisan config:cache
すると直ると思います。
まとめ
サービスプロバイダは、サービスコンテナを使用して様々な機能を提供するためのものです。register
ではサービスコンテナへの登録処理のみを行うということを把握しておきましょう。
