PHPのシグナルとスロット。 Qtと同じ。 まあ、ほとんど

シグナルとスロットは、一部のプログラミング言語とライブラリ(BoostやQtなど)で使用されるアプローチであり、「オブザーバー」パターンを実装して、繰り返しコードの記述を最小限に抑えることができます。 概念は、コンポーネント(多くの場合、ウィジェット)がイベントに関する情報を含む信号を送信できることです(たとえば、テキスト「単語」が選択され、2番目のタブが開かれました)。 また、他のコンポーネントは、特別な機能-スロットを介してこれらの信号を受信できます。 シグナルおよびスロットシステムは、グラフィカルユーザーインターフェイスの記述に適しています。 また、シグナル/スロットメカニズムは、非同期入出力(ソケット、パイプ、シリアルインターフェイスを備えたデバイスなど)またはイベントの通知に使用できます。 Qtライブラリでは、ロシア語のMeta-Object Compiler(Eng。)に感謝します。 コードのこれらのテンプレートセクションは自動的に生成されるため、登録/登録解除/呼び出しコードを記述する必要はありません。
ウィキペディアは私たちに伝えています。



PHPアプリケーションにはイベントループはありません。 要求を受け取り、応答しました。 それだけです。 ただし、「リクエストの受信」と「回答の提供」の間には何らかのアプリケーションライフサイクルが存在するため、すべてが失われるわけではなく、Webアプリケーションでこのメカニズムを使用できます。 学生の頃、私はC ++ / Qtでプログラミングし 、シグナルとスロットの実装が本当に好きでした。 結局のところ、素晴らしいアイデアです。 最も近いのは、Observerパターンです。 目標は1つですが、実装はまったく異なります。 小さなライブラリの形でこのメカニズムをphpに実装するようになりました。



信号とスロット



シグナルは、オブジェクトの内部状態について外部の世界に知らせることができるものです。 電話が鳴り、猫が鳴きます。 通話と鳴き声は、それぞれ電話と猫の信号です。 彼らはオブジェクトの内部状態の変化について私たちに知らせます:電話は休息状態から「あなたに電話をかける」状態になり、猫は「完全な猫」状態から「空腹の猫」状態になりました。



これらの信号には、どのような方法でも対応できます。 たとえば、パイプを拾うか、最後に猫に餌をやる。 信号に対する反応はスロットです。



プログラミングでは、オブジェクトの状態の変化に対応する必要があるときに、まったく同じ状況が発生します。 このために、信号とスロットのメカニズムが使用されます-オブジェクト間の通信を保証します。 私の意見では、Observerテンプレートとは異なり、使用する方が簡単で透過的です(ただし、Observer自体も非常に単純なテンプレートです)。



少し考えて、信号とスロットのメカニズムを実装するphp 用のコネクタライブラリを作成しました。 彼女を見てみましょうか?



設置



コネクタは作曲家パッケージとして利用できるため、インストールするために実行する必要があります

composer require fluffy/connector
      
      





またはcomposer.jsonファイルのライブラリに依存関係を追加します

 "require": { ... "fluffy/connector": "^1.0" }
      
      





そして実行する

 composer update
      
      







使用する



1.シグナル


オブジェクトが信号を発信できるようにするには、 SignalInterface



インターフェイスを実装し、対応するSignalTrait SignalTrait



を使用する必要がありSignalTrait



。 たとえば、ロガークラスがあり、ロギングが終了するたびにsomethingIsLogged



シグナルを送信するsomethingIsLogged



にします。

 <?php /** * @file * Contains definition of Logger class. */ use Fluffy\Connector\Signal\SignalInterface; use Fluffy\Connector\Signal\SignalTrait; /** * Class Logger. */ class Logger implements SignalInterface { use SignalTrait; public function log() { // Do logging stuff. ... // Emit signal about successfull logging. $this->emit('somethingIsLogged', 'Some useful data'); } }
      
      





シグナルを送信するには、 emit



メソッドを呼び出して、2つのパラメーターを渡す必要があります。シグナルの名前と、このシグナルによって送信されるデータです。 任意のタイプのデータを転送できます:文字列、数値、配列、またはオブジェクト。 以上です。 これで、ロガーオブジェクトは信号を外部に送信できます。 しかし、誰もこの信号に接続されていない限り、このオブジェクトが何か有用なものを報告していることを誰も知りません。 それを修正しましょう。



2.スロット


スロットは通常のクラスメソッドです。 スロットを持つクラスを作成しましょう。

 <?php /** * @file * Contains definition of Receiver class. */ /** * Class Receiver. */ class Receiver { public function slotReactOnSignal($dataFromSignal) { echo "Received data: $dataFromSignal"; } }
      
      







3.信号スロット接続


そのため、シグナルを持つLogger



クラスとスロットを持つReceiver



クラスがあります。 信号に応答するには、スロットを接続する必要があります。

 use Fluffy\Connector\ConnectionManager; $logger = new Logger(); $receiver = new Receiver(); ConnectionManager::connect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal'); $logger->log();
      
      





ConnectionManager::connect($sender, $signalName, $receiver, $slotName)



ConnectionManager::connect($sender, $signalName, $receiver, $slotName)



ことにより、ロガーオブジェクトの信号を受信者オブジェクトのスロットに接続しました。 これは、 $logger->log()



が呼び出される$logger->log()



に、 somethingIsLogged



ロガーが送信され、受信者スロットslotReactOnSignal



が応答することをslotReactOnSignal



ます。 必要な数の信号スロット接続を決定できます。 可能なすべてのタイプの接続が機能します。



1つのオブジェクトからの信号であるか、別のオブジェクトからの信号であるか、1つのオブジェクトのスロットであるか、または異なるかは関係ありません。



4.接続の種類


デフォルトでは、 ConnectionManager::connect()



メソッドは永続的な接続を作成します。 これは、信号の最初の送信後に接続が切断されないことを意味します。 ただし、5番目のパラメーター(接続の種類)として定数を渡すことにより、1回限りの接続を作成することができます。 例:

 use Fluffy\Connector\ConnectionManager; $logger = new Logger(); $receiver = new Receiver(); ConnectionManager::connect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal', ConnectionManager::CONNECTION_ONE_TIME); $logger->log(); // Log once again. $logger->log();
      
      





Logger::log()



への2回目の呼び出しの後、スロットは最初の送信後に信号から切断されるため、何も起こりません。



5.切断


特定の信号をもう聞きたくない場合は、単にその信号から切断します

 ConnectionManager::disconnect($logger, 'somethingIsLogged', $receiver, 'slotReactOnSignal');
      
      





すべての既存の接続をリセットする必要がある場合は、呼び出す必要があります

 ConnectionManager::resetAllConnections()
      
      







これは何のためですか?






プロジェクトリポジトリ: fluffy / connector



この行にたどり着くのが面白かったと思います。 批判や噂は大歓迎です。



UPD






All Articles