こんにちは。夏はやっぱり生ビール、@madapajaです。
PHP5.4+フレームワーク BEAR.Sundayを理解するためにRay.Diを触ってみるの巻 其の壱 : 今日も適当ダイアリー の続きです。
PHP5.4+フレームワーク BEAR.Sundayを理解するためにRay.Diを触ってみるの巻シリーズ
前回は、Ray を Composer 経由でインストールして User
クラスを作りました。
Ray を使わずに書いてみる
Ray を使ってみる前に、普通に PHP を書いて User
クラスを実行してみたいと思います。今回は Madapaja\Ray\Di\Sample01\App
クラスを下記のように書きました。
src/Madapaja/Ray/Di/Sample01/App.php
namespace Madapaja\Ray\Di\Sample01;
use Madapaja\Ray\Di\Sample01\Model\User;
class App
{
public function run()
{
$pdo = new \PDO('sqlite::memory:', null, null);
$user = new User($pdo);
$user->init();
$user->createUser('Koriym', mt_rand(18,35));
$user->createUser('Bear', mt_rand(18,35));
$user->createUser('Yoshi', mt_rand(18,35));
$users = $user->readUsers();
print_r($users);
}
}
そして上の App
クラスを実行するために下記のファイルを作ります。内容はオートローダを読み込んで App::run()
を実行するだけです。
main.php
require __DIR__.'/vendor/autoload.php';
use Madapaja\Ray\Di\Sample01\App;
(new App())->run();
ここまで出来たら php main.php
として実行してみます。
Array
(
[0] => Array
(
[Name] => Koriym
[Age] => 24
)
[1] => Array
(
[Name] => Bear
[Age] => 18
)
[2] => Array
(
[Name] => Yoshi
[Age] => 30
)
)
のように、結果が表示されたでしょうか?簡単ですね。というか、普通のPHPなので当たり前ですね。
Ray.Di でインジェクトしてみよう
やっと、Rayの出番です。Ray.Diを使って依存性を注入してみます。今回の場合は、 User
クラスへ PDO
を注入します。
Ray では DI や AOP の設定をモジュールという単位(クラス)で行います。モジュールはアプリケーションやフレームワークを構成する際に使われる知識を持っており、その知識をもとにインジェクターが依存を注入することで、適切なオブジェクトグラフを生成されることになります。
とりあえず、モジュールで DI と AOP の設定をするよ、ということが分かればOKです。
アノテーションの追加
モジュールを作る前に、User
クラスのコンストラクタへインジェクトを行うことを示すために、アノテーションを追加します。
src/Madapaja/Ray/Di/Sample01/Model/User.php
namespace Madapaja\Ray\Di\Sample01\Model;
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;
class User
{
private $db;
/**
* @Inject
* @Named("pdo=pdo_user")
*/
public function __construct(\PDO $pdo)
{
$this->db = $pdo;
}
// ...
13行目で @Inject
アノテーションによってインジェクトポイントだということを示し、14行目で @Named
アノテーションで pdo_user
という名前で(pdo
を)バインドすることを示します。
なお、5~6行目は @Inject
と @Named
アノテーションの名前空間を解決させるために use
しています。
UserModule を作る
ということで、User
クラスの構成設定を行う UserModule
を作ります。 モジュールは Ray\Di\AbstractModule
を継承し configure()
メソッド内で構成の設定を行います。
src/Madapaja/Ray/Di/Sample01/Module/UserModule.php
namespace Madapaja\Ray\Di\Sample01\Module;
use Ray\Di\AbstractModule;
class UserModule extends AbstractModule
{
protected function configure()
{
// bind dependency @Inject @Named("pdo_user")
$pdo = new \PDO('sqlite::memory:', null, null);
$this->bind('PDO')->annotatedWith('pdo_user')->toInstance($pdo);
}
}
DI の設定は 13 行目で行っており、PDO
クラスの pdo_user
という名前の箇所に PDO インスタンス($pdo
)をバインドしています。 (本来はインターフェースではない PDO クラスや、その実体(インスタンス)を使用しない方がいいのですが、ここではコードを簡単にするために許してもらいます。)
インジェクタ経由でインスタンスを取得する
これで準備が整いました。 App
クラスを書き変えてインジェクタを利用してみます。
src/Madapaja/Ray/Di/Sample01/App.php
namespace Madapaja\Ray\Di\Sample01;
use Ray\Di\Injector;
use Madapaja\Ray\Di\Sample01\Module\UserModule;
class App
{
public function run()
{
$di = Injector::create([new UserModule]);
$user = $di->getInstance('Madapaja\Ray\Di\Sample01\Model\User');
$user->init();
// ...
12行目で、今作った UserModule
を指定してインジェクタを生成し、13行目で実際に User
クラスのインスタンスを取得しています。 これで、依存がよしなに解決されるようになりました。
アノテーションのオートロードを設定
さっそく実行してみたいところですが、アノテーションのオートロードのためにもうひとつ処理を追加する必要があります。 これは BEAR.Sunday ではフレームワーク側でやってくれますので、今回のように Ray をスタンドアロンで利用する場合にのみ必要な設定です。
main.php でオートローダーを取得して、アノテーションレジストリにローダーを登録します。 実際のソースは下記のようになります。
main.php
use Doctrine\Common\Annotations\AnnotationRegistry;
use Madapaja\Ray\Di\Sample01\App;
$loader = require __DIR__.'/vendor/autoload.php';
AnnotationRegistry::registerLoader(array($loader, "loadClass"));
(new App())->run();
これでやっと実行できるようになりました。php main.php
を実行させて問題なく動くのを確認してみましょう。
@PostConstruct アノテーションによる初期化メソッドの定義
これまでUser
クラスを初期化するために、 App
クラスで User::init()
メソッドを呼び出していました。 これを @PostConstruct
アノテーションすることで、インジェクタに初期化メソッドの呼び出しを任せようと思います。
src/Madapaja/Ray/Di/Sample01/App.php
// ...
class App
{
public function run()
{
$di = Injector::create([new UserModule]);
$user = $di->getInstance('Madapaja\Ray\Di\Sample01\Model\User');
// $user->init();
// ...
App.phpの修正は、12行目を削除するだけです。
次に User
クラスにアノテーションを追加します。
src/Madapaja/Ray/Di/Sample01/Model/User.php
namespace Madapaja\Ray\Di\Sample01\Model;
use Ray\Di\Di\Inject;
use Ray\Di\Di\Named;
use Ray\Di\Di\PostConstruct;
class User
{
// ...
/**
* @PostConstruct
*/
public function init()
{
return $this->db->query('CREATE TABLE User (Id INTEGER PRIMARY KEY, Name TEXT, Age INTEGER)');
}
// ...
名前空間を use
して、@PostConstruct
アノテーションを追加するだけです。 これだけで、インジェクタの getInstance
メソッドでインスタンスを取得する際、コンストラクタ後にアノテーションしたメソッドが呼び出されるようになります。
いよいよ Ray.Aop の登板!
という所なのですが、またもや長くなってきた(というか疲れた)ので、其の参に続きます!にんにん!
(7/12追記)続き書きました!
参考リンク
PHP5.4+フレームワーク BEAR.Sundayを理解するためにRay.Diを触ってみるの巻シリーズ