お疲れ様です。ギークフィードエンジニアのサミーラです。私は一年ぐらい前からLaravelフレームワークでWEBシステム開発をしています。
Laravelによるプロジェクトの経験
- 通話録音システムの制御および表示Webシステム
- モバイルゲームのバックエンドシステム
- WEB電話帳システム
- IP-PBXのWEBプロビジョニングシステム。
今回は、「プロバイダー」または「サービスプロバイダー」と呼ばれるLaravelの非常に重要なポイントについて説明します。サービスプロバイダーは、プロジェクトとLaravelフレームワークのコア機能の初期化(ブートストラップ)の中心点です。
ブートストラップとは?
それは「オブジェクト、依存関係、イベントリスナー、ミドルウェア、サービスコンテナーへのルートなどを登録する」ことです。
単に、アプリケーションの起動時に(実際にリクエストが来たときに)必要なすべてのアイテムを作成し、すべてを1つのバッグに入れることです。その後、必要なときにいつでもそれらのものを使用できます。
config/app.phpに「providers」配列を見ると、アプリケーションのすべてのサービスプロバイダーが一覧表示されます。その一覧に長いリストが定義していますけど、各リクエストにその全てのサービスプロバイダーがロードされません。一部のクラスは「Deferred」しているため、各リクエストにロードされません。それについて、後で話しましょう。。
目次
サービスコンテナー(Service Container)とサービスプロバイダー(Service Provider)の関係性について
サービスプロバイダーを詳しく調べる前に、サービスコンテナーについて理解しておく必要があります。サービスコンテナは、アプリケーションのブートストラッププロセスで開始されたすべてのものが配置されるkey => valueの場所です。「Auto resolving/Dependency injectionなど」などの強力な機能があります。ものをサービスコンテナにバインド(配置)し、サービスコンテナからものを解決(取得)できます。
例:サービスコンテナーへのバインドと解決
1 2 3 |
app()->bind(‘example’, function(){ return “hello world”; }); |
1 |
app()->make(‘example’); //出力 [hello world] |
次に、サービスコンテナーに物をバインドするために使用されるのはサービスプロバイダーです。サービスプロバイダーには、2つの主要なメソッド「register/boot」が含まれています。Registerメソッドは、ものを(機能ではなく)サービスコンテナにバインドするために使用されます。
Laravelアプリケーションにリクエストが届くと、ロード(ブートストラップ)が開始されます。Laravelが最初に行うことは、すべての登録済みサービスプロバイダーのすべてのregisterメソッドを呼び出すことです(プロバイダーの登録方法については後で説明します)。次に、Laravelはすべてのbootメソッドを呼び出します。
したがって、サービスプロバイダーのregisterメソッドを使用してサービスコンテナーに何かをバインドしている場合、システムのブートストラップ後にすべてを使用できます。プロジェクト内のどこからでもコンテナからこれらのものを使用できます。
サービスプロバイダーは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class SampleServiceProvider extends ServiceProvider { /** * コンテナにバインディングを登録します */ public function register() { } /** * アプリケーションサービスをブートストラップします。 */ public function boot() { } } |
“Deferred” サービスプロバイダー
リクエストが来たときに、すべてのサービスプロバイダーが読み込まれるわけではありません。一部は「Deferred」です。それは何ですか? Deferredとは、サービスプロバイダーがすべてのリクエストに対してロードされるのではなく、特にそのプロバイダーがリクエストされた場合にのみロードされることを意味します。
サービスプロバイダーは、コンテナにバインディングを登録している場合にのみ「Deferred」にすることができます。bootメソッドに何かがある場合、そのサービスプロバイダーはDeferredにすることができません。
Deferredサービスプロバイダーは[\Illuminate\Contracts\Support\DeferrableProvider]インターフェイスと[provides]メソッドを使用します。「Provides」メソッドは、サービスコンテナーに登録されたアイテム(サービスプロバイダーによる)を返す必要があります。
簡単な例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Contracts\Support\DeferrableProvider; use App\Sample; //This is a custom class class SampleServiceProvider extends ServiceProvider implements DeferrableProvider { /** * Register bindings in the container. */ public function register() { $this->app->bind(Sample::class, function($app){ Return new Sample(); }); } /** * Get the services provided by the provider. */ public function provides() { return [Sample::class]; } } |
例「BIRD ZOO」を使って詳しく解説します
それでは、次の状況を考えてみましょう。
「BIRD ZOO」についてです。システムには、Bird、Food、AnimalServiceProvider、AnimalControllerクラスが含まれています。ディレクトリ構造は次のようになります、
ここでは、AnimalControllerクラスはBirdクラスを使用します。AnimalControllerクラスだけでなく、他のすべてのクラスでもBirdクラスを使用できます。そのため、AnimalServiceProviderは、クラスをサービスコンテナに登録することにより、アプリケーションでBirdクラスを使用できるようにします。ここでは、BirdクラスにはFoodクラスが必要です。
Laravelサービスコンテナの自動解決機能により、Foodクラスがインスタンス化され、Birdクラスに挿入されます。Laravelは「Reflection」という機能を使用してこれを実行します。
サービスプロバイダーの作成と使用
ここでは、上記の例を使用します。
phpクラスを作成し、必要なインポートとメソッドを追加することにより、サービスプロバイダーを手動で作成できます。しかし、Artisanコマンドを使用したほうが作成しやすいと思います。
1 |
php artisan make:provider AnimalServiceProvider |
AnimalServiceProviderは、Bird::classをキー「bird」でサービスコンテナにバインドします。ここでは、Food::classが作成され、サービスコンテナの自動解決を使用してBird::classに注入されます。サービスコンテナ内のオブジェクトがあるかどうかチェックして、オブジェクトが利用可能な場合はそれをそのまま渡し、オブジェクトがコンテナで利用できない場合(この例のように)、作成し、コンテナに入れて渡します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Animals\Bird; use App\Animals\Food; class AnimalServiceProvider extends ServiceProvider { /** * Register the Bird class instance to the container. * Food class will be auto injected */ public function register() { $this->app->bind('bird', function($app){ return new Bird($app->make(Food::class)); }); } } |
AnimalServiceProviderを作成したら、それをLaravelフレームワークに登録する必要があります。そのため、config / app.phpの「Providers」配列に次の行を追加します。
1 |
App\Providers\AnimalServiceProvider::class |
関連するBirdとFoodのクラスはこちらです。
Birdクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php namespace App\Animals; use App\Animals\Food; class Bird { private $food = null; public function __construct(Food $food){ $this->food = $food; } public function sound(){ return "tweet tweet"; } public function getFood(){ return $this->food; } } |
Foodクラス
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App\Animals; class Food { public function foodType(){ return "warms"; } } ?> |
これで、コンテナのBird::classとFood::classをどこからでも使用できます。クラスを何度も作成する必要はありません。サービスプロバイダーがクラスをインスタンス化してくれます。
クラスのインスタンスを使用する方法
1 2 3 4 |
$bird = app()->make('bird'); $returnText = "Sound : ". $bird->sound(); $returnText .= "<br>Food : ". $bird->getFood()->foodType(); echo $returnText; |
サービスプロバイダーを使うメリットとは
実際、サービスプロバイダー、サービスコンテナー、オブジェクトのバインド、およびそれらの使用は必ずしも必要ではありません。
ただし、複雑で適切に設計された、スケーラブルで保守可能なアプリケーションを作成する場合は、もちろん、プロバイダーを使用することをお勧めします。また、Laravelパッケージの作成を計画している場合は、プロバイダーを使用してパッケージをフレームワークに登録する必要があります。
例として,
動物をBirdからFishに変更する必要があると考えてください。したがって、AnimalServiceProviderでFish::classを実装し、BirdからFishにバインドを変更する必要があります。プロバイダがFish::classをコンテナにバインドしたので、Bird::classを使用する他のすべての場所は、以降Fish::classを使用します。
OR
Bird::classのコンストラクタを変更した場合でも、AnimalServiceProviderのregisterメソッドバインディングを更新する必要があり、その効果はすべての場所に適用されます。それで、アプリケーションは、サービスプロバイダーで本当にスケーラブルで保守可能になります。
Laravelのサービスプロバイダーの仕組みやメリットまとめ
サービスプロバイダーは、物事をサービスコンテナにバインドするために使用されます。サービスコンテナには、プロジェクト内のどこでも使用できるものが含まれています。
サービスプロバイダーには、「registerとboot」メソッドが含まれています。Providerのregisterメソッドで、リスナー、ルートをバインドしようとするべきではありません。リクエストがアプリケーションに届くと、すべてのサービスプロバイダーがブートストラップされます。「Deferred」サービスプロバイダーは、要求された場合にのみロードされます。サービスプロバイダーはconfig/app.phpファイルにリストおよび登録されます。
サービスプロバイダーを使用する必要はありませんが、プロバイダーとコンテナーを使用して、適切に設計されたスケーラブルで保守可能なシステムを作成できます。
ALL THE BEST!!! HAPPY & CLEAN CODING!!!
- SupervisorでLaravelのQueue worker管理 - 2021-07-27
- Laravelでバックグラウンド処理。。。 - 2021-03-22
- NATファイアウォール背後のサーバーをZabbixで監視するTips - 2020-09-09
- Laravelのパフォーマンスを向上しましょう - 2019-12-02
- Laravelのサービスプロバイダーの仕組みやメリットとは - 2019-09-04