Yii2 かんたんコンテナ

Yii2は便利なものや、強力なdebugツール等至れり尽くせりなフレームワークですが、
コンテナもシンプルで強力なものの一つです
振る舞いを変更したりサービスロケータにしてみたり
簡単に幅広く利用する事が出来ます

```php:Yii.php
class Yii extends \yii\BaseYii
{
}

spl_autoload_register(['Yii', 'autoload'], true, true);
Yii::$classMap = include(__DIR__ . '/classes.php');
Yii::$container = new yii\di\Container;
```
と実装されていますので、どこでも簡単に利用できます
ではいくつか利用方法を紹介しましょう！

## basic
```php
// 単体で利用
$container = new yii\di\Container;
// フレームワーク
\Yii::$container;
```
さっそくコンテナを利用してみます
まずは普通のクラスを作って、インスタンスを作ってみましょう

```php:service/Acme.php
namespace app\service;

/**
 * Class Acme
 * @package app\service
 */
class Acme
{

} 
```
上記のシンプルなクラスのインスタンスを取得する場合は

```php
$container->get('app\service\Acme');
```
となります
`di/Container.php`でbuildメソッドを利用してインスタンスを生成しています

## 引数利用
コンストラクタに引数を利用するクラスです

```php
class Acme
{
    protected $acme;

    public function __construct($message = "")
    {
        $this->acme = $message;
    }
}
```
Reflectionを使ってコンストラクタの引数を調べて、
必要に応じて引数を利用してインスタンスを生成するので、
引数が必要なもの下記の様にしてみましょう

```php
$container->get('app\service\Acme', ["yii2"]);
```
このあたりは他のコンテナライブラリやフレームワーク等と同じです

コンテナが返すものはインスタンスじゃなくてもOKです
文字列にすることもできます

```php
$container->set('hi', function () {
        return 'yii';
    }
);
$container->get('hi');
```
## プロパティにも
では下記の場合はどうでしょうか？
プロパティのみです

```php
class Acme
{

    public $acme;
}
```
この場合は、

```php
$container->set('hello', function () {
        return 'yii2';
    }
);

$container->get('app\service\Acme', [], [
        'acme' => $container->get('hello'),
    ]
);
```
上記の様にプロパティに対して代入することもできます

```php:di/Container.php
$object = $reflection->newInstanceArgs($dependencies);
foreach ($config as $name => $value) {
    $object->$name = $value;
}
```
di/Containerで、
newInstanceArgsでインスタンスを作成してプロパティに挿入する様に実装されています
シンプル！

```php
$container->get('app\service\Acme', [], [
        'acme' => function() {},
    ]
);
```
クロージャなどでも同様です
## setter
private, protectedのプロパティに対しては、
セッターを利用する事が出来ます

```php
class Acme extends Object
{

    public $acme;

    protected $private;

    public function setPrivate($private)
    {
        $this->private = $private;
    }
}
```
`yii\base\Object`を継承すると、マジックメソッドの`__set`を利用して
protectedにも対応する事が出来ます

そしてさらに、
インスタンス生成時に利用できる様に、コンテナにまとめて登録する事も出来ます

```php
$container->set('app\service\Acme', [
        'acme' => 'yii'
    ]
);
$container->get('app\service\Acme');
```
コンテナに登録するときに、`class`を利用するとそのインスタンスを返す様になります

```php
$container->set('acme.class', [
        'class' => 'app\service\Acme',
        'acme' => 'yii'
    ]
);
$container->get('acme.class');
```
すごい楽チンで多彩！それでいてシンプル故に早い！
下記の様な場合は、コンストラクタで記述されているクラスも自動で解決してくれます

```php
class Acme
{
    public $acme;

    /** @var \stdClass  */
    protected $class;

    /**
     * @param \stdClass $class
     */
    public function __construct(\stdClass $class)
    {
        $this->class = $class;
    }
}
```
## di
interfaceも使ってしまいましょう

```php
namespace app\service;

interface AcmeInterface
{

} 
```
こんな感じで実装してみます

```php
class Acme implements AcmeInterface
{
    public $acme;
}

class Nyaa implements AcmeInterface
{
    public $acme;
}
```
簡単に実装を入れ替える事が出来ます

```php
$container->set('app\service\AcmeInterface', 'app\service\Acme');
$container->get('app\service\AcmeInterface');

$container->set('app\service\AcmeInterface', 'app\service\Nyaa');
$container->get('app\service\AcmeInterface');
```
もちろんsingletonもあります
componentsと組み合わせたり、実装にあわせて自由に開発する事が出来ます
マニュアルやソースコードを読んで触ってみましょう！