localdisk

PHP とか Java とか Web とか好きなことを書きます。

AspectP開発中

PHPでAOPしてみた - localdiskで予告したとおり、本格的なAOPライブラリを現在開発中です。
名前はJavaAOPライブラリ「AspectJ」をもじって「AspectP」に決めました。Rubyに「AspectR」というのがあるようなので、これでよいかな…と思ってたらPythonAOP実装でAspectPというのがあるっぽい。
…まぁあまりメジャーなライブラリではないようなので気にしないようにします。ごめんなさい。以後気をつけます。
気を取り直して使い方などを説明しようと思います。

ポイントカットの方法

ポイントカットはコメントアノテーションで行うようにします。

<?php
/**
 * @Aspect('intercepter' => 'LoggerIntercepter')
 * こう書くとexecuteメソッドにLoggerIntercepterが適用されます
 */
public function execute(){
}

最初のバージョンはコメントアノテーションはメソッドのみ有効な形でリリースしようかと思います。その後は、コンストラクタAOPが出来たり、クラスにコメントアノテーションを書いて正規表現でポイントカットできるようにする予定です。こんな感じで。

<?php
/**
 * @Aspect('intercepter' => 'LoggerIntercepter', 'pointcut' => '*Action')
 * こう書くとHogeControllerの「Action」終わるメソッドにLoggerIntercepterが適用されます
 */
public class HogeController {
}

このへんはS2.PHP5に影響されてます。あんまり話題にのぼりませんがS2.PHP5はすごいですよ。今リリースされているRCはPHP5.3に対応していて名前空間をバリバリ使っているので勉強になります。

Intercepter

インターセプターは4種類用意します。

BeforeAdvice
Joinpointの前に呼び出されます。BeforeAdviceを実装したIntercepterはbeforeメソッドを実装しなければなりません。
AfterAdvice
Joinpointの後に呼び出されます。AfterAdviceを実装したIntercepterはafterメソッドを実装しなければなりません。
AroundAdvice
Joinpointの前後に呼び出されます。BeforeAdviceを実装したIntercepterはbefore, afterメソッドを実装しなければなりません。
ThrowAdvice
例外が発生した時に呼び出されます。ThrowAdviceを実装したIntercepterはthrowingメソッドを実装しなければなりません。

ここらへんの発想はSpringから頂きました。Intercepterは上記4つのアドバイスを実装する形になります。例えばLogerIntercpeterがAroundAdviceを実装している場合、適用したメソッドの前後でログが出力される、という感じになります。

設定ファイルでよるAOP

アノテーションを使用するとコードを見ると適用されているAOPがわかるので、気に入っているのですがクラスよりも大きなスコープでAOPを適用したい場合が不便になります。たとえば管理者用ディレクトリadmin配下のクラス全てにログイン用のIntercepterを適用したい場合とか。そんな時のために設定ファイルでもAOPを適用できるようにしたいと思います。iniかxmlyamlがファイル形式は決めていませんが…。

やろうかどうしようか迷っていること

関数にAOP
ReflectionFunctionというクラスがあるので関数でもAOPできると思います。でもそこまでやるメリットが浮かばないんですよね。これが出来たら非常にPHPっぽいとは思いますが。
エンハンスしてキャッシュ
前のエントリのブックマークコメントを見るとパフォーマンスを心配されている方がいましたので、ちょっと対策を考えてみました。PHPのリフレクションは割りと色々できるのでエンハンスしてキャッシュすることもできます。難しそうですが。

まとめ

基本的な仕様は固まってますが、どこまでやるかというのはまだ決めてません。なにかご意見・ご要望等ありましたらコメント欄にお願い致します。