Web開発者は同様の問題に直面しているだけでなく、コンポーネントデスクトップアプリケーションや複雑なシステムの設計にも関連しています。 そして、いくつかの成功したソリューションは、そのような開発からスパイされ、借りることができます。 この場合、シグナル/スロットアーキテクチャについて話します。これはQtライブラリに実装され( 詳細な説明 )、コンポーネント間の通信に使用されます。 同様の機能は、Web開発、この場合はPHPプロジェクトで非常に役立ちます。
私は個人的に、JavaScriptに似たPHPで十分なイベントを持っていません。Signal/ Slotを使用すると、サーバー側で同様の機能を使用できます。 つまり、各オブジェクトは何らかのイベント(シグナル)を生成でき、他のオブジェクトは必要なシグナルをサブスクライブし、シグナルが発生すると、指定されたシグナルをリッスンするすべての登録済み関数(スロット)が呼び出されます。 そのようなアーキテクチャの場合、登録されたすべての信号のリストを保存し、リスニング機能のレジスタを保持し、イベントが発生したときにそれらを正しい順序で開始する中間オブジェクトが必要です。 PHPプロジェクトのこのような機能に対する既成のソリューションはありますか、それとも独自のソリューションを作成する必要がありますか? もちろん、このようなスクリプトの作成は非常に簡単で、経験豊富な開発者はこれを行うのに1〜2日かかりますが、 ezComponentsフレームワークの 一部である既製のソリューションを使用することもできます。 Zend Frameworkのような高度で真面目なソリューション(申し訳ありませんが、まだそのようなモジュールはありません)。
このフレームワークには、アーキテクチャの主要コンポーネントを実装するezcSignalCollectionコンポーネントがあります。 オブジェクトのインスタンスを作成した後、 connectメソッドを呼び出すだけで、任意の数の信号とスロットを接続できます。 たとえば、呼び出しの時間に関する行を単に表示する関数_test_slot ()(エコー演算子を介して)が信号「test_alert」に応答するようにするには(信号は任意の行にできますが、事前定義された信号のリポジトリを作成するのが最善です)、接続するだけです。
$tmp = new ezcSignalCollection();
function _test_slot()
{
echo 'Called by test_alert signal!';
}
$tmp->connect("test_alert", "_test_slot");
//
$tmp->emit("test_alert");
// :
Called by test_alert signal!
接続後、指定された信号を生成する任意の場所でemitメソッドを呼び出すことができます。 接続するとき、関数名を文字列として渡す必要があることに注意してください(PHP関数call_user_funcが使用されるため )。これは最も単純な例です。 1つのイベント/シグナルで複数の機能をハングさせることができ、それらは接続された順序で実行されます。 ただし、この動作は常に役立つとは限りません。 これには優先度メカニズムがあります-各スロットに優先度レベル(整数、1〜65 536)を割り当てることができ、呼び出されると考慮されます-数字が小さいほど、このスロットは高くなります。つまり、優先度1のスロットが最初に実行されます。その後、最後まで。 複数のスロットの優先度が同じ場合(デフォルトでは1000)、接続順に実行されます。 優先度の設定は簡単です-3番目の引数で接続ラベルに必要な優先度を渡します。
機能のみをスロットとして使用できる場合、このコンポーネントの利点はほとんどありません。 しかし、 ezcSignalCollectionの機能ははるかに広く、オブジェクトのメソッドとしてスロットとして機能できます(ここでは、まだ1つのことを理解していません-オブジェクトが既に作成されている場合、このオブジェクトのメソッドが呼び出され、そうでない場合、新しいインスタンスが作成されますか?)、そして静的メソッド。 これを行うには、標準形式を使用します。配列では、クラス名が最初に文字列として表示され、次にメソッド名が表示されます。
シグナルとともにいくつかのパラメーターを送信する必要がある場合は、 emmitメソッドでの生成中にシグナル自体の後にそれらを追加する必要があります。 したがって、各関数に渡されるパラメーターを無制限に渡すことができます。 ただし、参照による値の受け渡しに関するニュアンスを考慮してください。詳細については、PHPマニュアルのcall_user_func_arrayセクションを参照してください 。
ただし、大規模で複雑なアプリケーションの場合、この機能だけでは不十分な場合があります。 そして、制限のためではなく、複雑さのために-信号は一意でなければなりませんが、統一されたシステムを作りたいという願望は、異なるモジュールが同じ信号を持つことができるという事実につながります。つまり、理解と読みやすさを促進するためにそれらを同じにすることが望ましい、しかし、それは不可能です。 ただし、解決方法があります。静的接続を作成し、同じクラスのオブジェクトによって生成された信号に応答するメソッドまたは関数を定義できます。 つまり、Cacheクラスによって生成された「delete_item」シグナルはハンドラーによって処理され、Newsクラスの継承者からの同じシグナルが独自の方法で処理されます。 同時に、静的に接続された機能が通常の機能の後に機能することを考えると、シグナルへの定期的なサブスクリプションと静的なサブスクリプションの両方を組み合わせることができます。 たとえば、両方のケースで_prepare_itemメソッドが呼び出され、その完了後に必要な静的に接続されたハンドラーが既に呼び出されます-これは実際には処理プリプロセッサーを実装できます。
静的スロットを実装するには、 ezcSignalCollectionオブジェクトを作成するときに、クラス名をコンストラクターに渡す必要がありますが 、残りのコードは変更せず、 ezcSignalStaticConnectionsクラスを使用して接続します。
このモジュール自体のコードは、些細ではないにしても非常に単純であり、Googleで検索した後(たとえば、 thisおよびthis )、いくつかのフォーラムで自分の実装のための他のオプションを見つけましたが、 ezComponentsのこのコンポーネントはさらに柔軟で機能的です。 プラグインを使用して柔軟なシステムを構築する場合、このメカニズムが役立つと思います。 ただし、モノリシックアプリケーションの場合でも、Signal / Slotの実装は、より柔軟で美しいアーキテクチャの実装に役立ちます。 試してみてください。