auraで覚える Dependency Injection


## Dependency Injectionって何？

Webプログラミング業界で最も有名なInjectionといえば「SQL Injection」ですね。
Injectionというと、何となく悪いことのような印象があるかもしれません。
また、Dependency Injectionは日本語で「依存性の注入」と訳されます。
この語彙からはヤバい感じしかしません。
![依存性の注入](http://livedoor.4.blogimg.jp/hatima/imgs/7/c/7c98d7b2.jpg)

そういった印象とは裏腹に、Dependency Injectionはソフトウェア開発において有用なデザインパターンの一つです。
Dependency Injectionについては、私なんかが説明するよりもずっと[わかりやすくて的確な情報](http://qiita.com/search?utf8=%E2%9C%93&q=Dependency+Injection&sort=rel)がQiitaにはたくさんあります。

## Dependency Injectionの方法

- コンストラクタインジェクション
- セッタインジェクション
 
以上の2種類の方法があります。
それぞれがどのようなものであるかについては、Qiitaでググると[たくさんの有用な情報](http://qiita.com/search?utf8=%E2%9C%93&sort=rel&q=%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF+%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3)が得られます。

## AuraでのDepencenty Injection

AuraにはDIコンテナがあります。
DIコンテナとは、DIの実装を楽にしてくれるツールです。

AuraのDIコンテナを利用したDependency Injectionの実装例です。

### コンストラクタインジェクション

```php:ConstructorInjection.php
<?php
$path = dirname(__DIR__);
require "{$path}/vendor/autoload.php";

class NichijouAnime {

	static protected $_roleList = [
		'boke', 'yarukinashi', 'joushikijin',
	];
	protected $_memberList;

	public function __construct($boke, $yarukinashi, $joushikijin) {
		foreach (self::$_roleList as $role) {
			$this->_memberList[$role] = $$role;
		}
	}
}

use Aura\Di\Container;
use Aura\Di\Factory;

$di = new Container(new Factory);

// あいうら
$di->set('aiura', $di->lazyNew('NichijouAnime'));

$di->params['NichijouAnime']['boke'] = 'kanaka';
$di->params['NichijouAnime']['yarukinashi'] = 'saki';
$di->params['NichijouAnime']['joushikijin'] = 'ayuko';

$aiura = $di->get('aiura');

var_dump($aiura);

// ゆゆ式
$di->set('yuyushiki', $di->lazyNew('NichijouAnime', [
	'boke' => 'yuzuko',
	'yarukinashi' => 'yukari',
	'joushikijin' => 'yui',
]));

$yuyushiki = $di->get('yuyushiki');

var_dump($yuyushiki);
```

```console_output
$ php ConstructorInjection.php
class NichijouAnime#10 (1) {
  protected $_memberList =>
  array(3) {
    'boke' =>
    string(6) "kanaka"
    'yarukinashi' =>
    string(4) "saki"
    'joushikijin' =>
    string(5) "ayuko"
  }
}
class NichijouAnime#8 (1) {
  protected $_memberList =>
  array(3) {
    'boke' =>
    string(6) "yuzuko"
    'yarukinashi' =>
    string(6) "yukari"
    'joushikijin' =>
    string(3) "yui"
  }
}
```

「あいうら」という日常系の四コマ漫画・アニメ作品には、ボケキャラ、やる気無いキャラ、わりと常識人キャラの3名が主に登場します。
同じく日常系四コマ漫画・アニメ作品である「ゆゆ式」も似たようなキャラ構成です。
ちなみに「あいうら」をローマ字で書くと「Aiura」です。「Aura」と似ています。

上記のコードでは、コンストラクタインジェクションでNichijouAnimeクラスのコンストラクタに値を与え、aiura と yuyushiki という2つのサービスを生成しています。
`$di->set('aiura', $di->lazyNew('NichijouAnime'));`としておくと`$di->get('aiura');`としたときにNichijouAnimeクラスのコンストラクタが呼び出されオブジェクトが生成されます。
コンストラクタの引数は、あいうらの例のように`$di->params[CLASS_NAME][PARAM_NAME] = VALUE;`といったように渡すか、ゆゆ式の例のように$di->lazyNew()の第二引数に配列で渡します。

また、パラメータの値にLazyNewのオブジェクトを渡すことも可能です。

```php
<?php
class Charactor {
	protected $_name;
	public function __construct($name) {
		$this->_name = $name;
	}
}

$di->set('aiura', $di->lazyNew('NichijouAnime'));
$di->params['NichijouAnime']['boke'] = $di->lazyNew('Charactor', ['name' => 'kanaka']);
$aiura = $di->get('aiura');
```

このコードでは CharactorクラスのオブジェクトがNichijouAnimeのコンストラクタに渡されて、aiuraサービスが生成されます。

### セッタインジェクション

```php
<?php
class NichijouAnime {

	static protected $_roleList = [
		'boke', 'yarukinashi', 'joushikijin',
	];
	protected $_memberList;

	public function setBoke($boke) {
		$this->_memberList['boke'] = $boke;
	}

	public function setYarukinashi($yarukinashi) {
		$this->_memberList['yarukinashi'] = $yarukinashi;
	}

	public function setJoushikijin($joushikijin) {
		$this->_memberList['joushikijin'] = $joushikijin;
	}

	public function getMemberList() {
		return $this->_memberList;
	}
}

$path = dirname(__DIR__);
require "{$path}/vendor/autoload.php";

use Aura\Di\Container;
use Aura\Di\Factory;

$di = new Container(new Factory);

$di->set('aiura', $di->lazyNew('NichijouAnime'));

$di->setter['NichijouAnime']['setBoke'] = 'kanaka';
$di->setter['NichijouAnime']['setYarukinashi'] = 'saki';
$di->setter['NichijouAnime']['setJoushikijin'] = 'ayuko';

$aiura = $di->get('aiura');

var_dump($aiura);

$di->set('yuyushiki', $di->lazyNew('NichijouAnime', [],
	[
		'setBoke' => 'yuzuko',
		'setYarukinashi' => 'yukari',
		'setJoushikijin' => 'yui',
	]
));

$yuyushiki = $di->get('yuyushiki');

var_dump($yuyushiki);
```

出力はコンストラクタインジェクションのときと同じです。

セッタインジェクションを用いる場合は、DIコンテナのsetterプロパティにセッタメソッドの引数に渡す値をセットします。
`$di->lazyNew()` の第三引数に配列で渡すこともできます。

また、生成するクラスのメソッドだけでなく、InterfaceやTraitのセッタメソッドを呼ぶことも可能です。

```php
trait NichijouAnimeTrait {
	public function setTitle($title) {
		$this->_title = $title;
	}
}

class NichijouAnime {
	use NichijouAnime;
	protected $_title;
}
$di->set('aiura', $di->lazyNew('NichijouAnime'));
$di->setter['NichijouAnimeTrait']['setTitle'] = 'aiura';
$di->get('aiura');
```

## 参考にしたサイト

http://auraphp.com/framework/2.x/ja/di/

## 最後に

DIコンテナは使用しなくてもDIの考えに則したコードは作成できる。
newでインスタンスを作ったり、セッタメソッドを直接呼んだ方がシンプルにかけるケースもあるだろう。

DIにおいて大切なのは、そもそもDIとは何なのかを理解すること。
これを機に、もっとちゃんと勉強をしようと思う。