例外処理とロギングのひな形
例外をキャッチしたときにしたいこと
- ログ取り
- エラー画面の表示
なので、Exceptionクラスを拡張して、上の2つのメソッドを追加する。
・exception.php
<?php /* */ class My_Exception extends Exception { protected $error_message; protected $template = "errors/500.phtml"; public function __construct($message, $code=0) { parent::__construct($message, $code); // $this->logging(); $this->display(); } public function logging() { $this->error_message = $this->createMessage(); Logger_Observer::notify("FATAL", $this->error_message); } public function createMessage() { return $this->getMessage() . ", StackTrace: " . $this->getTraceAsString(); } public function display() { $view = new View; if(Config::read("main", "debug")) { $view->assign("error_message", $this->error_message); } $view->render($this->template); } }
404 Not Foundな処理をしたいときは、この例外クラスを継承してテンプレートを404エラー用のものに変更すれば大丈夫。
ん?まあいっか。
Configとかは作ってるフレームワークの設定クラスなのであまり気にしない。
ロギングは例外以外でも使いたいので、別のクラスにして実行する。
・logger.php
<?php /* */ class Logger { protected $message; public function __construct($type, $message) { $this->message = $this->format($type, $message); } protected function format($type, $message) { $str = sprintf("%s [%s] %s", date("Y/m/d H:i:s"), $type, $message); return $str; } public function getMessage() { return $this->message; } } final class File_Logger extends Logger { public function __construct($type, $message) { parent::__construct($type, $message); $this->log(); } private function log() { error_log($this->message, 3, APP . DS . "logs/error.log"); } public static function raise($type, $message) { return new self($type, $message); } } final class Mail_Logger extends Logger { // メール処理を書く public static function raise($type, $message) { return new self($type, $message); } } // log observer class Logger_Observer { public function __construct() {} public static function run($type, $message) { $log_conf = Config::read("log"); if($log_conf["level"]) { if($log_conf["file"]) File_Logger::raise($type, $message); if($log_conf["mail"]) Mail_Logger::raise($type, $message); } } }
とりあえず、実行日時、エラーの箇所、エラーメッセージ、スタックトレース辺りを記録できればいいかなと思ったので、そういう感じにしてみました。
ファイルにログを取るときは、PHPの場合error_log関数で一発なので楽ですね。
ロギングの実行関数raiseを親クラス側で定義できればいいのだけど、継承したクラスでstaticな関数を実行すると、なぜか実行しているクラス名が親クラスになる。
これってどうしようもない問題なのかな?
そうだとすると、ロギングの子クラスでは全部宣言しないと駄目だ。。。
使いたいときは以下のように例外をキャッチして使う。
<?php function test() { throw new My_Exception("Raise My Exception. This is the message!'"); } try { test(); } catch(My_Exception $e) { die(); }
ログにはこんな感じで出力されます。
2009/02/15 22:30:04 [FATAL] Raise My Exception. This is the message! #0 /Users/cheesepie/Sites/test/exception_test.php(7): test() #1 {main}