PHPとアスペクト指向プログラミング

Javaの世界で非常に人気のあるアスペクト指向プログラミング(AOP)パラダイムは、何らかの理由でPHP開発で十分にカバーされていません。 この記事では、小さなフレームワークとモジュールを使用してAOPアプリケーションを作成するためのアプローチを紹介します。



アスペクト指向プログラミングについて簡単に



アスペクト指向プログラミングは、機能を分割してプログラムをモジュールに分割することを改善するという考え方に基づいたパラダイムです。

簡単に言うと、このアプローチの本質は、特定のイベント(メソッド呼び出しなど)が発生したときに開始する関数を作成することです。 定義に応じて、イベントが実行される前または後(またはその前後)に関数が起動されるため、ロギングからオブジェクトに関する情報のデータベースとの同期(永続性)まで、さまざまな操作を実行できます。

そのような機能が実行される条件は「結合ポイント」と呼ばれ、条件のグループは「カット」(ポイントカット)、そして機能自体は「アドバイス」と呼ばれます。

ほとんどの場合、ヒントは(メソッドをクラスに分類するように)アスペクトにグループ化されているため、アスペクトはいくつかの機能を実装する一連のヒントです。



PHPの実装



2つの明白な実装方法があります。

1)必要なヒントを呼び出すすべての潜在的な接続ポイントのラッパー関数を作成します。

2)メソッドを起動するプロセスにコードを埋め込みます。これにより、必要なヒントが実行されるか、対応する接続​​ポイントがない場合は実行されません。

最初の方法の主な欠点は冗長性です。 ラッパー関数を持たない既存のシステムにAOPを実装することを決定すると、タスクはさらに複雑になります。

2番目の方法はきれいに見えますが、追加の拡張機能をPHPに接続する必要があります。 彼について(方法)、さらに進んでいきます。



MethodInterceptモジュール



奇妙なことに、PHP5 +では、オブジェクトのメソッドの呼び出しをインターセプトできる拡張機能はありません。 見つかったのはInterceptだけで 、その開発は2005年のアルファリリースに焦点を合わせていました。 拡張機能は、別の機能の前後に何らかの機能を実行できます。 もちろん、PHP5のOOPでは機能しません。

それに基づいて、MethodInterceptを作成しました。これは、メソッド呼び出しのインターセプトに加えて、メソッドが呼び出されるオブジェクトとメソッドに渡される引数をインターセプト関数に渡すこともできます。

拡張機能のコンパイルは非常に簡単です(Linuxの例):

git clone git@github.com:kooler/PAF.git cd PAF/MethodIntercept phpize ./configure make
      
      





その結果、intercept.soファイルがモジュールフォルダーに表示されます。このフォルダーは、PHP拡張を含むフォルダーにコピーする必要があります(php -i | grep extension_dirを実行し、php.iniにextension = intercept.soを追加することで認識できます)。

上記のすべてが成功した場合は、intercept_add関数を使用することができます。この関数は、インターセプトするクラス->メソッド、呼び出す関数、インターセプトメソッド-前後の3つのパラメーターを取ります。



PHPアスペクトフレームワーク(PAF)



MethodInterceptを使用すると、メソッドを起動するプロセスにコードを埋め込むことができますが、これはいくつかの理由でAOPを完全に使用するには不十分です。

1.拡張機能はキューをサポートしていません-指定できるインターセプター関数は1つだけです。

2.インターセプターは関数にしかなれず、メソッドにはなれません;したがって、アドバイスをアスペクトにグループ化することは不可能です。

3.関数(intercept_add)を呼び出してインターセプターを指定するのはあまり便利ではありません。

上記のすべての実装をMethodInterceptに追加することはお勧めできません。そのタスクはメソッド呼び出しをインターセプトすることであり、AOPに必要なすべてのバンを提供するわけではないためです(このための拡張機能を別途作成する価値があるかもしれません)。

したがって、AOPの使用を簡素化する独自のミニフレームワークを作成することにしました。つまり、

1.注釈を使用して接続ポイントを定義できます

2.呼び出しキューの形成とintercept_addの実行を想定しています

3.アスペクトを作成できます

4.結合ポイントを定義するときに正規表現を使用できます

このフレームワークは、PHPアスペクトフレームワーク(または略してPAF)と呼ばれています: github.com/kooler/PAF



AOPの典型的な例-ロギング



AOP-ロギングの使用の古典的な例でのフレームワークの適用を検討してください。

クラスがあるとします:

 class Backet { public function order() { //  } public function createNew() { //  } }
      
      





ユーザーがバスケットを作成または作成するたびにメッセージを表示する(またはログに書き込む)と仮定します。 Loggerアスペクトを作成してみましょう。これには2つのヒントが含まれます。1つ目はバスケットの作成後に呼び出す必要があり、2つ目は作成後に呼び出す必要があります。

 class Logger extends Aspect { /* * @After(Backet->order) */ public function backetOrderMessage($params) { echo 'Backed has been ordered'; } /* * @After(Backet->createNew) */ public function backetCreatedMessage($params) { echo 'Backet has been created'; } }
      
      





アスペクトを登録し、実装機能を実行します。

 AspectRegistry::getInstance()->addAspect(new Logger); AspectRegistry::getInstance()->interceptAll();
      
      





後者は一度だけ呼び出す必要があります。すべての側面を登録した後、キューを作成してintercept_add関数を実行するのは彼女です。

各引数には1つの引数が渡されます。配列の最初の要素にはメソッドがインターセプトされたオブジェクトが含まれ、2番目の引数にはインターセプトされたメソッドが渡されます。 したがって、たとえば注文時にユーザー名を表示する必要がある場合、評議会は次のようになります。

 class Backet { public $username; … } class Logger extends Aspect { /* * @After(Backet->order) */ public function backetOrderMessage($params) { echo 'Backed has been ordered by user: '.$params[0]->username; } ... }
      
      





同様の例の完全なコード: github.com/kooler/PAF/blob/master/Framework/example.php



おわりに



現在、フレームワークはかなり初期の段階にあり、成長する余地があります。 プラグインを接続する機能、ベースとオブジェクトの同期を実装する機能(永続性)などを追加する予定です。 Javaでの人気から判断すると、このパラダイムは非常に興味深いものであり、PHPで生活する権利があります。

PHPで一般的なAOPが必要かどうかだけでなく、アドバイスやアイデアに感謝します。



All Articles