Laravelのサービスコンテナの働き(2)
クラスをnewする代わり
PHP(だけではないですが)では、あるクラスから別のクラスを利用しようとすると、原則そのクラスをnewしてインスタンスを生成する必要があります。リスト2ではBookクラスをnewすることで、利用できるようになります。
ところが、Laravelではこのnewそのもの、つまりインスタンスの生成をLaravelに任せることができます。それは、次のようなコードです。リスト4のnewBook2()メソッドをChap6Controllerクラスに追記してください。
<?php
〜省略〜
class Chap6Controller extends Controller
{
〜省略〜
public function newBook2()
{
$book = resolve("App\Chap6\Book"); // (1)
return "<p>newBook2()メソッドが実行されました。</p>";
}
}
動作確認を行うために、このメソッドnewBook2()をルーティング登録しましょう。ルーティングパターンは/chap6/newBook2とします。routes/web.phpにリスト5のコードを追記してください。
Route::get("/chap6/newBook2", "Chap6Controller@newBook2");
その後、以下のURLにアクセスしてください。
- http://localhost/firstlaravel/public/chap6/newBook2
すると、図2の画面が表示されます。
実行結果画面を見ると、確かにnewBook2()が呼び出され、Bookクラスのインスタンスが生成されているのがわかります。ところが、そのnewBook2()メソッド内では全くBookクラスをnewしていません。その代わりをしているのがリスト4の(1)のresolve()関数です。
このresolve()関数は、グローバル関数としてLaravel内で登録されており、この関数に引数としてクラスの完全修飾名を渡すと、該当クラスを探し出し、そのインスタンスをリターンしてくれる仕組みとなっているのです。その役割を担っているのがサービスコンテナ、つまりLaravelの中心となるApplicationインスタンスなのです。
サービスコンテナによるメソッドインジェクション
このように、サービスコンテナは、Laravelアプリ内に存在するクラスというクラスを管理し、必要とあれば、その時点でそのクラスのインスタンスを渡せるようになっているのです。それを手動で行う関数がresolve()です。一方、自動で行う方法もあります。それが、メソッドインジェクションと呼ばれるものです。
実際にコードで確認していきましょう。リスト6のnewBook3()メソッドをChap6Controllerクラスに追記してください。
<?php
〜省略〜
class Chap6Controller extends Controller
{
〜省略〜
public function newBook3(Book $book)
{
return "<p>newBook3()メソッドが実行されました。</p>";
}
}
動作確認を行うために、このメソッドnewBook3()をルーティング登録しましょう。ルーティングパターンは/chap6/newBook3とします。routes/web.phpにリスト7のコードを追記してください。
Route::get("/chap6/newBook3", "Chap6Controller@newBook3");
その後、以下のURLにアクセスしてください。
- http://localhost/firstlaravel/public/chap6/newBook3
すると、図3の画面が表示されます。
この実行結果画面を見ると、Bookクラスのインスタンスは確かに生成されているのですが、リスト6のnewBook3()メソッド内には、Bookクラスをnewするコードも、resolve()でインスタンスを取得するコードも存在しません。ここでポイントとなるのはnewBook3()メソッドの引数です。
Laravelでは、コントローラクラスのメソッドの引数として型指定を行うと、その型に該当するクラスを探し出し、インスタンスを渡す仕組みがあります。これもサービスコンテナの働きです。
サービスコンテナによるコンストラクタインジェクション
引数を使ってインスタンスを渡すこの仕組みは、コントローラクラスのメソッドだけでなく、コンストラクタにも有効です。例えば、リスト8のようなコードです。
<?php
〜〜省略
use App\Chap6\Magazine;
class Chap6Controller extends Controller
{
private $magazine;
public function __construct(Magazine $magazine)
{
$this->magazine = $magazine;
}
〜省略〜
}
Chap6Controllerにリスト8の太字のuse文と、プロパティ、コンストラクタを追記してください。ここで利用しているMagazineクラスは、例えば、リスト9のようなクラスです。
<?php
namespace App\Chap6;
class Magazine
{
public function __construct()
{
print("<p>Magazineクラスのコンストラクタが実行されました。</p>");
}
}
追記、クラスファイルの作成が終了したら、前項でアクセスした以下のURLにもう一度アクセスしてください。
- http://localhost/firstlaravel/public/chap6/newBook3
すると、今度は図4の画面が表示されます。
図3と見比べると表示が1行増えており、これがまさにMagazineクラスのインスタンスが生成されたことを物語っています。そのMagazineクラスはChap6Controllerクラスのコンストラクタの引数として記述されています。このように、コントローラクラスのコンストラクタに型指定された引数がある場合、Laravelのサービスコンテナは、そのインスタンスを自動生成して渡してくれる仕組みとなっているのです。
