web-dev-qa-db-ja.com

PHPイベントリスナーのベストプラクティスの実装

PHPでCMSのようなシステムを作成しようとしています。可能な限りモジュール式で拡張可能にします。

PHP(Drupalシステムの非常に単純化されたバージョン)、フックを作成する)短い例で実装するのもいいでしょう。

48
H.Josef

実装の観点からこれを行うには、実際には3つの異なる方法があります(これらはOOデザインパターンですが、必要に応じて機能的または手続き的に実装できます)。

1。オブザーバーパターン

Observer Pattern を実装できます。基本的に、イベントを発生させることができるものはそれぞれ対象になります。次に、聞きたいクラス/コードは、具体的に聞きたいものにバインドします。したがって、Fooというコントローラーがあるとします。聞きたい場合は、$fooController->attach($observer);を呼び出すことができます。その後、コントローラーが何かを言いたいときはいつでも、すべてのオブザーバーにイベントをディスパッチします。

これは(クラスが実行していることを拡張するための)通知システムに非常に適しています。コードの動作をリアルタイムで変更するにはあまり適していません。

2。デコレータパターンデコレータパターン も実装できます。基本的に、変更するオブジェクトを取得し、変更したいことを行う新しいオブジェクトに「ラップ」します。これは、動作を変更および拡張するのに非常に適しています(ラップされたクラスの機能を選択的にオーバーライドできるため)。

インターフェイスを定義し、オブジェクトがそれらに準拠することを期待している場合、これは非常にうまく機能します。インターフェースがない場合(または適切に使用しない場合)、デコレーターパターンでできることのほとんどは失われます。

また、これは実際にはイベントを実行する方法ではなく、オブジェクトの動作を変更する方法であることに注意してください。

3。メディエーターパターン

Mediator を使用することもできます。基本的に、リスナーを追跡する1つのグローバルメディエーターが必要です。イベントをトリガーする場合、イベントをメディエーターに送信します。メディエータは、どのリスニングオブジェクトがそのイベントを受信するかを追跡し、メッセージを適切に渡すことができます。

これには、中心的であるという利点があります。複数の送信者が同じイベントを送信できることを意味し、リスナーにそれを送信した人に違いはありません...

ブログ投稿でこのトピックを拡張しました。

130
ircmaxell
/*
 Example 1: 
 event::bind('blog.post.create', function($args = array())
 {
    mail('[email protected]', 'Blog Post Published', $args['name'] . ' has been published');
});

 Example 2: 
 event::trigger('blog.post.create', $postInfo);
*/

class event
{
    public static $events = array();

    public static function trigger($event, $args = array())
    {
        if(isset(self::$events[$event]))
        {
            foreach(self::$events[$event] as $func)
            {
                call_user_func($func, $args);
            }
        }

    }

    public static function bind($event, Closure $func)
    {
        self::$events[$event][] = $func;
    }
}
33
Codebeat

これは私がいくつかのプロジェクトでそれをやった方法です

すべてのオブジェクトは、new演算子の代わりにコンストラクター関数で作成されます。

_ $obj = _new('SomeClass', $x, $y); // instead of $obj = new SomeClass($x, $y);
_

これには、生のnewと比較して多くの利点があります。イベント処理の観点から、_new()は作成されたすべてのオブジェクトのリストを維持することが重要です。

このリストを反復処理するグローバル関数send($message, $params)もあり、オブジェクトがメソッド「on_ $ message」を公開している場合、このメソッドを呼び出してparamsを渡します。

_function send() {
    $_ = func_get_args();
    $m = "on_" . array_shift($_);
    foreach($_all_objects as $obj)
        if(method_exists($obj, $m))
            call_user_func_array(array($obj, $m), $_);
}
_

したがって、たとえば、send('load')は、定義されているすべてのオブジェクトに対して_on_load_メソッドを呼び出します。

13
user187291

PHP 5.3(したがってリッチクロージャーにアクセスできる))を使用している場合、 Lithium のイベント/フィルターシステムは、私がベースとして使用するものです [〜#〜] aop [〜#〜] PHPでの設計。

4
scoates