DIについては、DI(依存性注入) を参照
DIコンテナは、DIのインスタンス生成を、別のファイルでコンテナ化して解決しようという設計パターンです。
まず、共通で使う Animalクラスを用意します。
手っ取り早くファイル分割せず Animal.php にクラス(Dog、Cat)を記述しました。
interface Animal {
public function bow();
}
class Dog implements Animal {
public function bow() {
echo 'wan! wan!'.PHP_EOL;
}
}
class Cat implements Animal {
public function bow() {
echo 'nya-! nya-!'.PHP_EOL;
}
}
下記のサンプルはコンストラクタ内で Dog を生成して鳴きます。
class AnimalConsole {
protected $dog;
public function __construct() {
$this->dog = new Dog();
}
public function bow() {
$this->dog->bow();
}
}
$animal_console = new AnimalConsole();
$animal_console->bow();
この場合、コンストラクタで new Dog() するため、Dogが実装できるまで AnimalConsole が実装できません。
コンストラクタの引数に、Dog、Cat インスタンスを注入します(コンストラクタインジェクション)
他の記事をみているとこれで「DI」となってますが、まだ Dog に依存しているため Cat に修正したい場合に手間がかかります。
require_once 'Animal.php';
class AnimalConsole {
protected $dog;
public function __construct(Dog $dog) {
$this->dog = $dog;
}
public function bow() {
$this->dog->bow();
}
}
$animal_console = new AnimalConsole(new Dog());
$animal_console->bow();
今度は Dog、Cat 両方扱えるように Amimal を引数とします。
require_once 'Animal.php';
class AnimalConsole {
protected $animal;
public function __construct(Amimal $animal) {
$this->animal = $animal;
}
public function bow() {
$this->animal->bow();
}
}
$animal_console1 = new AnimalConsole(new Dog());
$animal_console1->bow();
$animal_console2 = new AnimalConsole(new Cat());
$animal_console2->bow();
これで、Dog、Cat どちらでも注入できるようになりました。
インスタンスを直接渡すのではなく、コンテナ(箱)内でインスタンスを作成して処理するのが、DIコンテナです。
今回は、composerのContainerライブラリ「pimple」を利用しています。
$ composer require pimple/pimple ~3.0
下記の場合、Dog、Cat のインスタンスをコンテナ化しています。
また、$container['animal'] では、インスタンスを簡単に切り替えることができます。
require_once 'Animal.php';
require_once __DIR__.'/../vendor/autoload.php';
use Pimple\Container;
class AnimalConsole {
protected $animal;
public function __construct(
Animal $animal
) {
$this->animal = $animal;
}
public function bow() {
$this->animal->bow();
}
}
$container = new Container();
$container['dog'] = function($c) {
return new Dog();
};
$container['cat'] = function($c) {
return new Cat();
};
$container['animal'] = function($c) {
return $c['dog'];
};
$container['animalConsole'] = function ($c) {
return new AnimalConsole($c['animal']);
};
$container['animalConsole']->bow();
Container の部分はファイル分離する必要はあります。