はじめに
依存性の注入とコンストラクタインジェクションについて調べてみました。Laravelを使っています。
依存性の注入によって何が解決されるのか
デモ用にRegisterServiceクラスとUserクラスを用意しました。RegisterService
クラスのuserInfoRegister
メソッドに登録情報を渡すと、UserクラスのcalcAge
メソッドが呼び出され、誕生日を元に年齢を計算する処理です。(内容は適当です)
=>これはクラスが別クラスと依存関係にある
処理だと言えます。
class RegisterService
{
public function userInfoRegister($info) {
$user = new User();
$user->calcAge($info['birthday']);
}
}
class User {
public function calcAge($birthday) {
// 誕生日から年齢を計算する処理
}
}
上記はのRegisterService
クラスは、userInfoRegister
メソッドでUser
クラスのインスタンスを生成して利用しています。User
クラスの動作にはRegisterService
が必ず必要になります。
=>つまり、依存しています。
次に特定クラスとの依存関係を排除した
処理に書き換えます↓
class RegisterService
{
public function userInfoRegister(User $user, $info) {
$user->calcAge($info['birthday']);
}
}
このように記述することで、クラスやメソッド内で利用する機能を外部から渡すことができるようになります。これがDI(依存性の注入)
と呼ばれるものです。
クラスの差し替えが必要になった場合でも、クラス同士が密接に依存しなくなったため、修正やテストが少なくなるメリットがあります。
コンストラクタインジェクション
クラスのコンストラクタの引数でインスタンスを注入する方法は、コンストラクタインジェクション
と呼ばれます。コンストラクタインジェクションでは、機能を渡されるクラスのコンストラクタの仮引数で、必要なクラスをタイプヒンティング
で指定します。
*タイプヒンティングとは、関数が引数を受け取る際の型宣言のことですね。
引数が何のオブジェクトやインターフェースなのか、またもや数値なのか配列なのかなどを指定することが出来ます。
class RegisterService
{
private $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function register($info)
{
$this->userRepository->create($info);
}
}
コンストラクタ仮引数の定義から、タイプヒンティングがクラス名やインターフェースであればその解決を行い、取得したインスタンスをコンストラクタメソッドの引数に渡します。
インターフェース名の場合は、解決方法がbindされている必要があります。
おわりに
Laravelを使っていると当たり前に出てくるDIやコンストラクタインジェクションですが、何をやっているのかあまり分かっていませんでした。便利ですよね。