こんにちは。呼ばれて飛び出てジャジャジャジャーン、@madapajaです。
PHP5.4+フレームワーク BEAR.Sundayを理解するためにRay.Diを触ってみるの巻シリーズ
続きです。 前回は、Ray.Di を使って依存性の注入を行ってみました。 今回は、Ray.Aop でインターセプターを使い、アスペクト指向プログラミングの体験を中心に進めてみたいと思います。
前回の補足
…と、その前に前回の補足を。
@PostConstruct
アノテーション
前回、@PostConstruct
アノテーションによって初期化メソッド(__construct()
後に実行するメソッド)の定義を行いました。
これはコンストラクタでやるのと、何が違うのでしょうか? 今回のサンプルの場合、コンストラクタ上で呼び出しても挙動は変わりません。
なぜコンストラクタで行わないのか、その理由を3つほど考えてみました。(@koriymさんからもアドバイスをもらいました)
1つめは、関心を分離させるためです。
コンストラクタでは文字通り構造を構成する(つまり、プロパティへの代入)のみに徹し、@PostConstruct
内でその構成されたオブジェクトに対しての初期化処理を記述することで関心を分離させられます。
2つめは、@PostConstruct
では全ての依存が注入されているのが保証されています。
前回のサンプルではコンストラクタへのインジェクションを行いましたが、Ray.Di ではSetterを使ったインジェクションも可能です。コンストラクタでも、Setterでも注入するという点では同じですし、挙動も基本的に変わりませんが、Setterインジェクションを行うことで、traitを利用しやすくなります。(実際に、BEAR.Sundayではtraitを利用して、テンプレートエンジンを注入したり、様々な箇所で使用されています。)
Ray.Diの内部の挙動は、コンストラクタへの注入後に、Setterへの注入が行われ、最後に @PostConstract
が呼ばれます。
たとえば、複数のSetterインジェクションがあるような場合、それらの複合的な設定を行うには、全ての注入が保証されている @PostConstruct
内でしか初期化できない処理も考えられるでしょう。
3つめは、これは副次的な特徴ですが @PostConstruct
では、同時にインターセプタを利用することが可能です。(逆に言えば、コンストラクタ内から別メソッド呼び出してもインターセプトされません。)
Ray.Di で、Injector::getInstance()
を行うと、そのクラスの依存が解決した後に、依存を注入しオブジェクトを構成させ、その後にウィーバー(インターセプトを織り込む)され、最後に @PostConstruct
が呼び出されます。
そのため、このアノテーション内では同時にインターセプトを利用することもできる、というわけです。
モジュールの作り方について
モジュールの分割単位は1)機能の関心ごと2)動作モード などで分割します。sandboxアプリではDevModule(動作モード)がフレームワークモジュール、機能のモジュール、アプリケーションモジュール等をinstallしてます。
— BEAR.Sundayさん (@BEARSunday) 7月 12, 2012
機能はたとえばDbなら Database\PdoModule にするのか Database\DoctrineOrm にするのかといった具合です。そのモジュール内では必要なDI、AOP設定を行います。
— BEAR.Sundayさん (@BEARSunday) 7月 12, 2012
とあるように、モジュールは関心ごとに分離すべきです。(今回はサンプルなので…)
Ray.Diには、あるモジュールの中から他のモジュールをインストール(追加設定のような感じ)する機能があります。
機能・関心ごとにモジュールを分離させることで、たとえば、実行(本番、テスト、開発)モードが要求する機能や関心を、必要に応じて構成させることができるようになります。
これは、下のつぶやきにもあるように、BEAR.Sundayの大きな特徴の一つです。
ここが他のFWのイベントによる機能拡張と違うところで、FW内のコードでイベント(シグナル)を発行してApp側でコールバックをアタッチするのではなくて、サービスコンポーネントそのものをDIで入れ替え、その振る舞いをAOPで変更します
— BEAR.Sundayさん (@BEARSunday) 7月 12, 2012
すべてのメソッドにインターセプタをバインドしてみる
では、ようやく本編です。
続きを読む