SymfonyEventDispatcher→Symfony2(PR4)EventDispatcherの変更点
この記事は、Symfony アドベントカレンダー 2010 に参加しています。
Symfony Advent 2010 : ATND
http://www.symfony.gr.jp/adventcalendar/2010
前の記事
先日、Observerパターンから学ぶSymfonyEventDispatcherの実装というエントリでsymfony1.4でのEventDispatcherの実装についてご紹介しました。
今回は、12/01に公開されたSymfony2 PR4のEventDispatcherでの変更点と追加機能についてご紹介します。
クラス図比較
Symfony2でのEventDispatcherは、1系とおおまかな作りは変わっていませんが、メソッド名の変更や細かい機能追加がいくつかあります。
二つをクラス図に落としてみたので比較してみましょう。
変更点
それではまず変更点について説明していきます。
Symfony2では、クラス内の主要なパラメータの取得や設定を行うためのアクセサの名前を、get(), set(), all()などのメソッド名に統一するポリシーとなりました。
http://docs.symfony-reloaded.org/master/contributing/code/conventions.html
このため、Eventクラス内の以下のメソッド名もこのポリシーに従い変更されています。
- getParameters() → all()
- offsetExists(name) → has(name)
- offsetGet(name) → get(name)
- offsetSet(name, value) → set(name, value)
また、1系ではdisconnect時にイベント名+listenerを指定するようになっていましたが、今回からはlistener指定はなくなりイベントを丸ごと削除するようになっています。
以下の機能は廃止されています。
- ArrayAccessのimplements
- offsetUnset(name)メソッドの実装(ArrayAccessのimplementsをなくしたため)
追加機能
次に追加機能についてです。
新しいEventDispatcherでは、priorityの概念が導入されました。
listenerの登録時に、priority(優先度)を指定することが出来ます。
優先度はデフォルト値が0となっていて、-10〜10の間で指定することが出来ます(この範囲外の値も使えますが目安としては-10〜10みたいです)。登録されたlistenerは、このpriorityの順でソートされ、値の低い方から実行されます。
getListeners()メソッドでは、優先度順に並び替えられたlistenerを得ることが出来ます。
サンプルプログラム
前回のエントリで紹介したサンプルプログラムと同じ物を、今回も実装してみます。
<?php require_once "EventDispatcher/Event.php"; require_once "EventDispatcher/EventDispatcher.php"; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\Event; class greetingListener { public function __construct() {} public function update(Event $event) { $hour = $event->get("hour"); if ($hour >= 5 && $hour < 11) { echo "おはよう",PHP_EOL; } elseif ($hour >= 11 && $hour < 19) { echo "こんにちは",PHP_EOL; } else { echo "こんばんは",PHP_EOL; } } } class FacemarkListener { public $facemarks = array("\(^o^)/", "(・∀・)", "(´・ω・`)"); public function __construct() {} public function update(Event $event) { $key = array_rand($this->facemarks, 1); echo $this->facemarks[$key]; } } $dispatcher = new EventDispatcher(); $grListener = new GreetingListener(); $fmListener = new FacemarkListener(); $dispatcher->connect("test.greeting", array($grListener, "update"), 5); // test.greetingというイベントに対してGreetingListenerのupdate処理をpriority=5で登録 ・・・1 $dispatcher->connect("test.greeting", array($fmListener, "update"), -10); // test.greetingというイベントに対してFacemarkListenerのupdate処理をpriority=-10で登録 ・・・1 // 状態変化をイベントとしてdispatcherに通知 ・・・2、3 $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>7))); $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>12))); $dispatcher->disconnect("test.greeting"); // test.greetingというイベントの登録を解除 ・・・4 $dispatcher->notify(new Event(null, "test.greeting", array("hour"=>23))); // イベントの登録が解除されたので何も起こらない ・・・5
実行結果
\(^o^)/おはよう (´・ω・`)こんにちは
前回と同様、dispatcherにはあらかじめイベント名とListenerの処理を2つ登録しておきます(1)。このとき、priorityを指定します。時刻が変化するとそれをイベントとしてdispatcherに通知します。(2、3)
dispatcherでは、通知を受けると、受け取ったイベント名に対して登録されているLitenerの処理を呼び出します。
今回はFacemarkListenerを優先するようpriorityをつけたので、登録順は逆ですが顔文字の方が先に出力されています。
test.greetingイベントの登録を解除(4)すると、次の通知から出力はされません(5)。
その他
リクエスト情報のプロファイリングを行うSymfony Profilerからイベントの一覧を見ることが出来るようになりました。
これは便利!
まだ簡単なサンプルでしか確認できていませんが、実装も以前よりシンプルになり、より使いやすくなった印象を受けました。
少し長くなりましたが、本日のエントリは以上です。Symfony2の本リリースが待ち遠しいですね。
Symfonyアドベントカレンダー、明日の担当はid:Fivestarです!