Maple: ブラウザにエラーメッセージを出したい

現在のMapleはエラーが発生しても、ブラウザにそのエラーを表示してくれません。その代わりに、ログファイルにエラーが出力されます。

僕は、開発中はブラウザにエラーメッセージを出力してほしい派なので、ちょっと今のMapleに不満を持っています。

そこで、考えました。
以下の3点がポイントです。

  1. エラー出力をブラウザにも表示するようなFilterを作成(仮にDebugFilterと呼ぶ)
  2. set_error_handler()でエラーハンドラを登録
  3. trigger_error()でエラーを出力

1.のようにしておけば、設定ファイルを変更すれば、いつでもエラー出力をoffにできます。
エラーメッセージのon/off機能は、開発終了後の本番環境を考えると必須の機能です。

問題は2.です。
今まで、set_error_handler()は単に関数しか登録したことがありませんでした。
今回は、DebugFilterのメンバー関数にエラーハンドラを持たせたいので、ちょっとした工夫が必要になります。
普通の関数をエラーハンドラにしてしまうと、 maple.iniを読み込むのが大変になるので。(Filter::getAttribute()を呼び出したいわけです。)

ネットで調べていたら、参考になる記事が見つかりました。
Debugging PHP Code
以下のコードは、その記事からポイントだけを取り出したコードです。
このコードを発見するのに結構苦労しました。

class Debugger {
[...]
     set_error_handler(array($this, 'errorHandler'), E_ALL ^ E_NOTICE);
[...]
    function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
    {
[...]
    }
[...]


この方法で、DebugFilter内にエラーハンドラを持たせることができます。

後は、エラーをトリガーしてやりたい所にtrigger_error()を書くだけです。
エラーメッセージの重複がありますが、アイデアということでご勘弁を。

$ cd ~/public_html/php/maple/maple-3.0.0
$ vi maple/filter/Filter_Action.class.php
[...]
        if ($this->getSize() > 0) {
            $attributes = $this->getAttributes();
            foreach ($attributes as $key => $value) {
                if (preg_match("/^ref:/", $value)) {
                    $value = preg_replace("/^ref:/", "", $value);
                    $component =& $container->getComponent($value);
                    if (is_object($component)) {
                        $attributes[$key] =& $component;
                    } else {
                        // BEGIN ysano2005
                        trigger_error("不正なコンポーネントが設定ファイルで指定されています($value)", E_USER_ERROR);
                        // END
                        $log->error("不正なコンポーネントが設定ファイルで指定されています($value)", "Filter_Action#execute");
                    }
                }
            }
            BeanUtils::setAttributes($action, $attributes);
        }
[...]

ここまでが核になる処理です。
後は、

  • Smartyで使えるデバッグ用テンプレートを用意
  • 綺麗に整形してブラウザにエラーメッセージを出力

するだけです。

PHPの組み込み関数であるdebug_backtrace()を使えば、コールスタックが見られるようになり、さらにエラーの特定がスムーズになるかもしれません。

以上、アイデアでした。