generated at
Service providers
公式ドキュメント

概要
Laravelアプリケーションのbootstrapに責任を持つ
Service providersによって、すべてのLaravelのコアサービスと自作のアプリケーションがbootstrapされる
bootstrapとは、次のようなものをregisterすること
sercive container binding
Service containerにインタフェースとインスタンスの対応づけを登録する
event listener
middleware
router

LaravelにはどんなService Providerがロードされるのか
config/app.php providers arrayに自作アプリケーションでロードするservice provideのリストがある
その多くが deferred なproviderで、すべてのリクエストで毎回ロードされるわけではなく、必要なときのみロードされる。

自作のService Providersを書く
ServiceProviderクラスを書く
Illuminate\Support\ServiceProvider を継承し register() boot() をもつ
Service Providerのメソッドの呼ばれる順序
1. 全Providerの register()
2. 全Providerの boot()
この順序が担保されているため、bootの中では $app が使える
$app はほかのService ProviderでbindingがすんだService containerが利用できるオブジェクト
register()
Service containerにbindする処理のみを書く
インタフェースにインスタンスをbindするのが典型的な使い方kadoyau
注意:それ以外のいかなるevent listenerやroutesや機能の一部をかいてはいけない
まだロードしていないサービスを意図せずService Providerから使うことを防ぐため
boot()
> This method is called after all other service providers have been registered, meaning you have access to all other services that have been registered by the framework:
つまり、Service Providerの boot() ではタイプヒントすると、Service containerによりDIが行われる
php
public function boot(ResponseFactory $response) { $response->macro('caps', function ($value) { // }); }


bindingsとsingletons
service providerで単純なbindingをたくさんregisterするときに便利な機能
service providerがロードされる時点でプロパティがチェックされて結合を登録する
使わない場合
php
$this->app->bind( ServerProvider::class, // インタフェース DigitalOceanServerProvider::class //実装クラス );
使う場合
php
class AppServiceProvider extends ServiceProvider { /** * 登録する必要のある全コンテナbinding * * @var array */ public $bindings = [ ServerProvider::class => DigitalOceanServerProvider::class, ];

サービスプロバイダを登録する
Service Providerを書きおわったら、 config/app.php に登録する
プロバイダを追加する際にはこの配列に追加する

LaravelアプリケーションがService Providersのboot/registerを呼ぶ流れ
1. deferredServices 配列にdifferedされるServiceProviesを登録する
Service Providers作成時にdeferフラグを立てて登録しておくと、サービスプロバイダのクラス名とサービスリストをlaravelは保持している
たぶんこれが bootstrapPath().'/cache/services.php に保存されるkadoyau
2. differedなサービスプロバイダを初期化する
アプリケーション起動時にbootstrapされるクラスが$bootstrappersとして定義されている
\Illuminate\Foundation\Bootstrap\RegisterProviders を含む
$bootstrappers に登録されたbootstrap classが上から順に実行される
Illuminate\Foundation\Application->registerConfiguredProviders() ProviderRepository->load()を呼び出す
getCachedServicesPath() が返す実態は $this->bootstrapPath().'/cache/services.php'
このファイルには providers deferred などの配列が定義されている
services.php
<?php return array ( 'providers' => array ( 0 => 'Illuminate\\Auth\\AuthServiceProvider', 1 => 'Illuminate\\Broadcasting\\BroadcastServiceProvider', 2 => 'Illuminate\\Bus\\BusServiceProvider', // 省略 ), 'deferred' => array ( 'Illuminate\\Broadcasting\\BroadcastManager' => 'Illuminate\\Broadcasting\\BroadcastServiceProvider', // 省略 ),
addDeferredServices()を呼ぶことで、service providerがdefferedServicesに登録される
ここまではアプリケーションの初期化プロセスで行われる。まだ実態は作られていないことに注意
実際に使うときがくると、 Illuminate\Foundation\Application->loadDeferredProvider() から registerDeferredProvider() 呼ばれ、前記services.phpで定義されている deferred なServiceProviders(BroadcastManagerとか)が初期化される
各Service Providerのregister()やboot()が呼ばれて、インタフェースに対する具象クラスを作成する
これはどこかから呼ばれる?
$bootstrappers 最後 Illuminate\Foundation\Bootstrap\BootProviders bootstrap() 呼び出されることで Illuminate\Contracts\Foundation\Application->boot() が呼び出される
各ServiceProviderの boot() メソッドが順次呼び出される


Deferred Provider
providerでService containerにバインドするだけ、bindが実際に必要になるまでregisterを遅らせるほうがパフォーマンス上有利
Laravelはdefferedなサービスプロバイダによって提供されるサービスの一覧をコンパイルして、サービスプロバイダの名前とともに保存している。実際にサービスのうちの一つが必要になったときに、サービスプロバイダをロードする