Yii2は便利なものや、強力なdebugツール等至れり尽くせりなフレームワークですが、
コンテナもシンプルで強力なものの一つです
振る舞いを変更したりサービスロケータにしてみたり
簡単に幅広く利用する事が出来ます
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
// 単体で利用
$container = new yii\di\Container;
// フレームワーク
\Yii::$container;
さっそくコンテナを利用してみます
まずは普通のクラスを作って、インスタンスを作ってみましょう
namespace app\service;
/**
* Class Acme
* @package app\service
*/
class Acme
{
}
上記のシンプルなクラスのインスタンスを取得する場合は
$container->get('app\service\Acme');
となります
di/Container.php
でbuildメソッドを利用してインスタンスを生成しています
引数利用
コンストラクタに引数を利用するクラスです
class Acme
{
protected $acme;
public function __construct($message = "")
{
$this->acme = $message;
}
}
Reflectionを使ってコンストラクタの引数を調べて、
必要に応じて引数を利用してインスタンスを生成するので、
引数が必要なもの下記の様にしてみましょう
$container->get('app\service\Acme', ["yii2"]);
このあたりは他のコンテナライブラリやフレームワーク等と同じです
コンテナが返すものはインスタンスじゃなくてもOKです
文字列にすることもできます
$container->set('hi', function () {
return 'yii';
}
);
$container->get('hi');
プロパティにも
では下記の場合はどうでしょうか?
プロパティのみです
class Acme
{
public $acme;
}
この場合は、
$container->set('hello', function () {
return 'yii2';
}
);
$container->get('app\service\Acme', [], [
'acme' => $container->get('hello'),
]
);
上記の様にプロパティに対して代入することもできます
$object = $reflection->newInstanceArgs($dependencies);
foreach ($config as $name => $value) {
$object->$name = $value;
}
di/Containerで、
newInstanceArgsでインスタンスを作成してプロパティに挿入する様に実装されています
シンプル!
$container->get('app\service\Acme', [], [
'acme' => function() {},
]
);
クロージャなどでも同様です
setter
private, protectedのプロパティに対しては、
セッターを利用する事が出来ます
class Acme extends Object
{
public $acme;
protected $private;
public function setPrivate($private)
{
$this->private = $private;
}
}
yii\base\Object
を継承すると、マジックメソッドの__set
を利用して
protectedにも対応する事が出来ます
そしてさらに、
インスタンス生成時に利用できる様に、コンテナにまとめて登録する事も出来ます
$container->set('app\service\Acme', [
'acme' => 'yii'
]
);
$container->get('app\service\Acme');
コンテナに登録するときに、class
を利用するとそのインスタンスを返す様になります
$container->set('acme.class', [
'class' => 'app\service\Acme',
'acme' => 'yii'
]
);
$container->get('acme.class');
すごい楽チンで多彩!それでいてシンプル故に早い!
下記の様な場合は、コンストラクタで記述されているクラスも自動で解決してくれます
class Acme
{
public $acme;
/** @var \stdClass */
protected $class;
/**
* @param \stdClass $class
*/
public function __construct(\stdClass $class)
{
$this->class = $class;
}
}
di
interfaceも使ってしまいましょう
namespace app\service;
interface AcmeInterface
{
}
こんな感じで実装してみます
class Acme implements AcmeInterface
{
public $acme;
}
class Nyaa implements AcmeInterface
{
public $acme;
}
簡単に実装を入れ替える事が出来ます
$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と組み合わせたり、実装にあわせて自由に開発する事が出来ます
マニュアルやソースコードを読んで触ってみましょう!