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です!


Symfony Advent 2010であなたの記事を公開してみませんか?

Symfony Advent 2010では12月1日から12月24日までを使って日替わりでsymfonyでイイなと思った小さなtipsから内部構造まで迫った解説などをブログ記事にして公開していくイベントです。

参加についてはATNDで参加表明の上、Google
GroupのSymfony Advent 2010に追加リクエストを送信ください。

Symfony Advent 2010チーム一同、あなたの参加をお待ちしております。

日本Symfonyユーザー会
Symfony アドベントカレンダー2010