Laravelのサービスプロバイダ
前節で紹介したサービスコンテナの働きには少し問題があります。この節では、その確認とそれを解決する仕組みとして、サービスプロバイダを紹介します。
コンストラクタの引数があるクラスのインスタンスの取得
前節で例に挙げたBookクラスやMagazineクラスは、そのクラス自体をnewする際に引数は不要でした。では、インスタンスを生成、つまり、newする際に引数が必要なクラスではどうなるのでしょうか。例えば、リスト10のようなクラスです。
<?php namespace App\Chap6; class Note { public function __construct(string $name) { print("<p>".$name."のNoteクラスのコンストラクタが実行されました。</p>"); } }
このクラスをnewする際は、例えば、以下のように引数を渡す必要があります。
$note = new Note("しんちゃん");
このNoteクラスのインスタンスをサービスコンテナ経由でもらうとするなら、どうなるでしょうか。もし、resolve()関数を使うならば、以下のように第2引数として連想配列の形で指定することが可能です。
$note = resolve("App\Chap6\Note", ["name"=>"しんちゃん"]);
第2引数で指定する連想配列は、「引数名=>値」の形で指定します。
サービスプロバイダ
では、メソッドインジェクションやコンストラクタインジェクションでインスタンスをもらう場合はどうなるでしょうか。例えば、リスト11のnewNote()メソッドのような場合です。
<?php 〜省略〜 class Chap6Controller extends Controller { 〜省略〜 public function newNote(Note $note) { return "<p>newNote()メソッドが実行されました。</p>"; } }
ここで追記したnewNote()メソッドをルーティング登録しましょう。ルーティングパターンは/chap6/newNoteとします。routes/web.phpにリスト12のコードを追記してください。
Route::get("/chap6/newNote", "Chap6Controller@newNote");
その後、以下のURLにアクセスしてください。
- http://localhost/firstlaravel/public/chap6/newNote
すると、これはエラーとなり、図5の画面となります。
![図5: newするときの引数がなくエラーとなった画面](http://cz-cdn.shoeisha.jp/static/images/article/11865/11865_005.png)
引数を渡すことができないので、当然です。
これを解決する仕組みとしてLaravelにはサービスプロバイダというのがあります。サービスプロバイダは、サービスコンテナ経由で取得するインスタンスの生成処理を担うクラスです。
実際に作成しましょう。リスト13のNoteServiceProviderクラスをapp/Providersディレクトリ内に作成してください。
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use App\Chap6\Note; class NoteServiceProvider extends ServiceProvider // (1) { public function register() // (2) { $this->app->bind("App\Chap6\Note", function($app) { $name = "しんちゃん"; $note = new Note($name); // (3) return $note; // (4) }); } }
サービスプロバイダは、(1)のようにServiceProviderクラスを継承して作ります。その上で、(2)のregister()メソッド内に以下の構文で該当クラスのインスタンス生成処理を記述します。
$this->app->bind("該当クラスの完全修飾名", function($app) { 該当クラスのインスタンスを生成し、リターン });
リスト13では、該当クラスがApp\Chap6\Noteですので、このクラスを(3)でnewし、それを(4)でリターンしています。この方式を利用すると、new時に引数を渡すことができるだけでなく、newしたインスタンスに対してさまざまな設定を行ったりした上でリターンすることもできます。
ただし、このサービスプロバイダはクラスを作成しただけでは利用できません。利用するには、config/app.phpに登録する必要があります。app.phpは連想配列が記述されているだけのファイルです。そのキーprovidersにサービスプロバイダクラスを登録します。リスト14の太字の1行を追記してください。
<?php return [ 〜省略〜 'providers' => [ 〜省略〜 App\Providers\NoteServiceProvider::class, ], 〜省略〜 ];
ここまで追記できたら、先のURLにもう一度アクセスしてください。図6の画面が表示され、無事、サービスプロバイダ経由で生成されたNoteインスタンスを、サービスコンテナがメソッドインジェクションで渡してくれているのが確認できます。
![図6:サービスプロバイダ経由でインスタンスを取得した画面](http://cz-cdn.shoeisha.jp/static/images/article/11865/11865_006.png)
まとめ
今回は、インスタンスの取得を自動化してくれる機能としてLaravelのサービスコンテナとインスタンスの生成処理を担うサービスプロバイダを紹介しました。
次回は、Laravelアプリでエラーや例外が発生した場合の処理を扱うエラーハンドラを紹介します。