今までも何度かやったDI(Dependency Injection = 依存性の注入)について。
以前のリンク
DIとはシンプルに言うと?
あるプログラムとあるプログラムを疎結合にしておき(切り離し)、外部から入力可能にしておくこと(これを注入などと言っています。)
だと解釈しています。
具体的に例をみていこうと思います。
サンプルコードと解説
Pet.php
1 2 3 4 5 6 7 8 9 10 11 |
<?php /** * インターフェイス */ interface Pet { public function getName(); public function bark(); } |
Cat.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php require_once 'Pet.php'; class Cat implements Pet { private $name; public function __construct($name) { $this->name = $name; } public function getName() { echo "cat name is " . $this->name . "\n"; } public function bark() { echo 'nyanya' . "\n"; } } |
Dog.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php require_once 'Pet.php'; class Dog implements Pet { private $name; public function __construct($name) { $this->name = $name; } public function getName() { echo "dog name is " . $this->name . "\n"; } public function bark() { echo 'wanwan' . "\n"; } } |
Animal.php
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 27 |
<?php /** * DIコンテナを使わないDI * */ require_once 'Pet.php'; require_once 'Cat.php'; require_once 'Dog.php'; $animal = new Animal(new Dog('pochi')); $animal->showPetProf(); class Animal{ private $pet; public function __construct(Pet $pet) { $this->pet = $pet; } public function showPetProf() { $this->pet->getName(); $this->pet->bark(); } } |
上記の $animal = new Animal(new Dog('pochi'));の部分が依存性(AnimalはDogに依存しています)を注入していることになります。
プログラムをこのように書くことによってインスタンスの生成部分が仮にnew Cat(‘tama’) になってもAnimalには一切影響がありません。
もしこう言った考えがなく、Animalの中でDogやCatを生成していた場合、変更がききません。
DIコンテナとは?
上記のような非常に簡単な例だった場合はいいのですが、クラスが何十にもあった場合は、このような注入作業が大変になります。
Animalの引数がめちゃくちゃいっぱいになっちゃいますよね・・・・
この場合、Animalとサブクラス群(DogやCat)を結びつける専用の仕組みが必要になります。
それがDIコンテナと言われるものです。
サンプルコードと解説
PHPではpimpleと言うシンプルなDIコンテナが使えます。
di_config.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php use Pimple\Container; $container = new Container(); $container['pet.name'] = ''; $container['pet'] = $container->factory(function ($c) { //猫の場合 return new Cat($c['pet.name']); //犬の場合 //return new Dog($c['pet.name']); }); $container['animal'] = $container->factory(function ($c) { return new Animal($c['pet']); }); |
Animal.php
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 27 28 29 30 31 32 33 |
<?php /** * DIコンテナを使ったDI * */ require_once 'Pet.php'; require_once 'Cat.php'; require_once 'Dog.php'; require_once "../../vendor/autoload.php"; require_once "di_config.php"; $container['pet.name'] = 'tama'; $animal = $container['animal']; $animal->showPetProf(); class Animal { private $pet; public function __construct(Pet $pet) { $this->pet = $pet; } public function showPetProf() { $this->pet->getName(); $this->pet->bark(); } } |
上記のようにプログラムを作っておくことで、変更があってもdi_config.phpのみに集中し、Animal.phpに変更が少ないないことが特徴です。
https://github.com/umanari145/phptips/tree/master/di/type2
参考リンク