Symfonyコンポーネント、イベントディスパッチャー(理論、パート2)

画像
こんにちは これは、 SymfonyドキュメントのEvent Dispatcherコンポーネントへの翻訳の2番目の部分です最初の部分はこちらです。 翻訳の2番目の部分は、Event Dispatcherコンポーネントを使用するための一般的なレシピのコレクションです 上記の例をテストするために、Symfonyフレームワークを接続する必要はありません- 最初のパートで述べたように、コンポーネントはフレームワークから独立しています。 繰り返しになりますが、 Symfony 2で使用するためにSymfonyコンポーネントのコードが処理されていることに注意してください(PHP> = 5.3.2)。 この翻訳は、Event Dispatcherコンポーネントの安定バージョンを指します しかし、コンポーネントの安定バージョンと Symfony 2の現在の バージョンを比較することで理解できるように、機能に大きな違いはありません。つまり、 ドキュメントは有用で、コンポーネントの新しいバージョン(PHP> = 5.3.2)を使用します。 それでは始めましょう。

Event Dispatcherオブジェクトの機能を見てみましょう


sfEventDispatcherクラスのコードを見た場合、クラスはシングルトン設計パターンに基づいて機能しないことに注意してください(静的getInstance()メソッドはありません)。 これは、単一のPHPリクエストで複数の競合するイベントディスパッチャを使用する場合があるため、意図的に行われます。 しかし、イベントと対話するかイベントを生成するオブジェクトにディスパッチャーを渡す方法が必要であることも意味します。

依存性注入パターンを使用して、オブジェクトにイベントディスパッチャーオブジェクトを含めることをお勧めします。

: (Fowler) 3 , : (interface injection), , ; (setter injection), (setter), ; (constructor injection), .
  1. : (Fowler) 3 , : (interface injection), , ; (setter injection), (setter), ; (constructor injection), .
  2. : (Fowler) 3 , : (interface injection), , ; (setter injection), (setter), ; (constructor injection), .
  3. : (Fowler) 3 , : (interface injection), , ; (setter injection), (setter), ; (constructor injection), .
コンストラクター注入を使用できます。
class Foo {
protected $dispatcher = null ;

public function __construct(sfEventDispatcher $dispatcher) {
$ this ->dispatcher = $dispatcher;
}
}

またはインストーラー注入(セッター注入):
class Foo {
protected $dispatcher = null ;

public function setEventDispatcher(sfEventDispatcher $dispatcher) {
$ this ->dispatcher = $dispatcher;
}
}
これらの方法のどれを使用するかを決めるのは好みの問題です。 オブジェクトは作成段階で完全に初期化されるため、コンストラクター注入を使用することを好みます。 ただし、依存関係のリストが大きい場合は、特にオプションの依存関係の場合、インストーラー実装を使用するのが最善の方法です。

注:前の2つの例のように依存性注入を使用する場合、 Symfony依存性注入コンテナーを簡単に使用して、これらのオブジェクトをよりエレガントに管理できます。

メソッドの呼び出しの前または直後に何かを行う


メソッド呼び出しの前または直後に何かを実行する場合は、メソッドの最初または最後でそれぞれイベントを宣言できます。
class Foo
{
// :
// ( ):
// static public function do_before($arr){
// echo "before!!!";
// }

public function send($foo, $bar)
{
// -
$ event = new sfEvent($ this , 'foo.do_before_send' , array( 'foo' => $foo, 'bar' => $bar));
// : :
// $this->dispatcher->connect('foo.do_before_send', 'Foo::do_before');
$ this ->dispatcher->notify($ event );

//
// $ret = ...;

// -
$ event = new sfEvent($ this , 'foo.do_after_send' , array( 'ret' => $ret));
$ this ->dispatcher->notify($ event );

return $ret;
}
}

クラスへのメソッドの追加


多くのクラスが互いにメソッドを追加できるようにするには、この方法で、拡張するクラスで__call()マジックメソッドを宣言できます。
class Foo
{
// ...

public function __call($method, $arguments)
{
// 'foo.method_is_not_found'
//
$ event = new sfEvent($ this , 'foo.method_is_not_found' , array( 'method' => $method, 'arguments' => $arguments));

// $method
$ this ->dispatcher->notifyUntil($ event );

// ?
if (!$ event ->isProcessed()) {
throw new sfException(sprintf( 'Call to undefined method %s::%s.' , get_class($ this ), $method));
}

// ,
return $ event ->getReturnValue();
}
}

次に、ハンドラーを保持するクラスを作成します。
class Bar
{
public function addBarMethodToFoo(sfEvent $ event )
{
// 'bar'
if ( 'bar' != $ event [ 'method' ])
{
//
return false ;
}

// ( foo)
$foo = $ event ->getSubject();

// bar
// , ,
// :
// $arguments = $event['arguments'];
$arguments = $ event [ 'parameters' ];

// -
// ...

//
$ event ->setReturnValue($someValue);

//
return true ;
}
}

最後に、Fooクラスに新しいbarメソッドを追加します。
$dispatcher->connect( 'foo.method_is_not_found' , array($bar, 'addBarMethodToFoo' ));

引数を変更する


メソッドを実行する直前に外部クラスがメソッドに渡された引数を変更できるようにするには、メソッドの先頭にフィルターイベントを追加します。
class Foo
{
// ...

public function render($template, $arguments = array())
{
//
$ event = new sfEvent($ this , 'foo.filter_arguments' );
// : :
// $this->dispatcher->connect('foo.filter_arguments', array(new Bar(), 'filterFooArguments'));
$ this ->dispatcher->filter($ event , $arguments);

//
$arguments = $ event ->getReturnValue();

// ...
// :
// return $arguments;
}
}

このようなクラスはフィルターとして機能します。
class Bar {
public function filterFooArguments(sfEvent $ event , $arguments) {
// :
// $arguments = array('33', '44');
$arguments[ 'processed' ] = true ;
return $arguments;
}
}

今のところすべてです。 さらに、PHP 5.3.2のコンポーネント新しいバージョンが 、PHP 5.2の対応する安定 バージョンとどのように異なるかについて説明したいと思います。 または、 Dependency Injectionコンポーネントについて書き始めます。 また、Sensio Labsがコードをテストする方法(たとえば、PHPUnitを使用する同じコンポーネント)について書くことは興味深いと思います。 また会うまで。

Source: https://habr.com/ru/post/J90829/


All Articles