Zend Framework 2 のイベントの流れをログる

Zend Framework のスケルトンアプリケーションのイベントの流れをログってみました。

## 方法

application.config.php の service_manager で SharedEventManager のファクトリを次のように設定します。

```php:application.config.php
    // ...snip...

    'service_manager' => array(
        'invokables' => array(
            'SharedEventManager' => null,
        ),
        'factories' => array(
            'SharedEventManager' => function(){
                $em = new \Zend\EventManager\SharedEventManager();
                $em->attach('*', '*', function (\Zend\EventManager\EventInterface $ev) {
                    $log = sprintf("%-20s%-40s%s", $ev->getName(), get_class($ev->getTarget()), get_class($ev));
                    error_log($log);
                }, PHP_INT_MAX);
                return $em;
            },
        ),
    ),

    // ...snip...
```

## 結果

前から順番に「イベント名」「ターゲットのクラス」「イベントオブジェクトのクラス」です。

IndexController の index アクションは次のようになりました。

```text
loadModules        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule.resolve Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule         Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
mergeConfig        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModules.post   Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
bootstrap          Zend\Mvc\Application                   Zend\Mvc\MvcEvent
route              Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Application\Controller\IndexController Zend\Mvc\MvcEvent
render             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
response           Zend\View\View                         Zend\View\ViewEvent
finish             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
sendResponse       Zend\Mvc\SendResponseListener          Zend\Mvc\ResponseSender\SendResponseEvent
```

ためしに IndexController の index アクションで例外を投げると次のようになりました（dispatch.error が増えています）。

```text
loadModules        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule.resolve Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule         Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
mergeConfig        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModules.post   Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
bootstrap          Zend\Mvc\Application                   Zend\Mvc\MvcEvent
route              Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Application\Controller\IndexController Zend\Mvc\MvcEvent
dispatch.error     Application\Controller\IndexController Zend\Mvc\MvcEvent
render             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
response           Zend\View\View                         Zend\View\ViewEvent
finish             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
sendResponse       Zend\Mvc\SendResponseListener          Zend\Mvc\ResponseSender\SendResponseEvent
```

ためしに application.config.php で config_cache を有効にしてみると次のようになりました（mergeConfig が減ってます）。

```text
loadModules        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule.resolve Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule         Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModules.post   Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
bootstrap          Zend\Mvc\Application                   Zend\Mvc\MvcEvent
route              Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Application\Controller\IndexController Zend\Mvc\MvcEvent
render             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
response           Zend\View\View                         Zend\View\ViewEvent
finish             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
sendResponse       Zend\Mvc\SendResponseListener          Zend\Mvc\ResponseSender\SendResponseEvent
```

ためしに AbstractHttpControllerTestCase でテストケースを作って phpunit から実行してみると次のようになりました（sendResponse が減ってます）。

```
loadModules        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule.resolve Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModule         Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
mergeConfig        Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
loadModules.post   Zend\ModuleManager\ModuleManager       Zend\ModuleManager\ModuleEvent
bootstrap          Zend\Mvc\Application                   Zend\Mvc\MvcEvent
route              Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Zend\Mvc\Application                   Zend\Mvc\MvcEvent
dispatch           Application\Controller\IndexController Zend\Mvc\MvcEvent
render             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
renderer           Zend\View\View                         Zend\View\ViewEvent
renderer.post      Zend\View\View                         Zend\View\ViewEvent
response           Zend\View\View                         Zend\View\ViewEvent
finish             Zend\Mvc\Application                   Zend\Mvc\MvcEvent
```

## この方法の問題点

`$sharedEvents->attach('*', '*', .. )` とすると下記のような問題があるので注意が必要です。

[php - Zend\Session\Container Session validation failed exception -- Object(Closure) ZF2 - Stack Overflow](http://stackoverflow.com/questions/17428778/zend-session-container-session-validation-failed-exception-objectclosure-zf "php - Zend\Session\Container Session validation failed exception -- Object(Closure) ZF2 - Stack Overflow")

と思ったのですが null を返しているときにセッションのバリデーションが失敗するのは不具合の扱いで 2.3.2 では修正されるようです。

 - https://github.com/zendframework/zf2/pull/6147
 - https://github.com/zendframework/ZendDeveloperTools/pull/146