異常信息的捕獲對編程測試有着重要的意義,這裏結合觀察者模式,探索如何處理異常信息。php
關於觀察者模式,若是尚未接觸過的話,博客園有不少優秀的博友作了詳細的 解釋。筆者以爲,所謂觀察者模式,必須有兩個重要組成部分:一個主題對象,多個觀察者。在使用的時候,咱們能夠將觀察者像插頭同樣插到主題對象這個插座上,利用主題對象完成相應功能。編程
既然觀察者要做爲插頭,必需要有一個統一的口徑才能插到相同的插座上,於是先定義一個接口,Exception_Observer.php:測試
<?php /** * 定義的規範 */ interface Exception_Observer{ public function update(Observer_Exception $e); } ?>
相對於衆多觀察者,咱們首先應該關注惟一的主題對象,Observer_Exception.php:ui
<?php class Observer_exception extends Exception{ public static $_observers=array(); public static function attach(Exception_Observer $observer){ self::$_observers[]=$observer; } public function __construct($message=null,$code=0){ parent::__construct($message,$code); $this->notify(); } public function notify(){ foreach (self::$_observers as $observer) { $observer->update($this); } } }
咱們能夠清楚地看到,靜態變量$_observers用來放置插入的觀察者,notify()用來通知全部觀察者對象。this
這裏須要注意 $observer->update($this); 裏面 $this 的用法,不少初學者會感到「原來 $this 也能夠這麼用啊」。spa
一個小問題: $_observers 不是靜態變量可不能夠? 這個問題咱們後面回答。插件
定義兩個觀察者,原則上實現接口所定義的功能。設計
Email_Exception_Observer.php:日誌
class Emailing_Exception_Observer implements Exception_Observer{ protected $_email="huanggbxjp@sohu.com"; function __construct($email=null) { if ($email!==null&&filter_var($email,FILTER_VALIDATE_EMAIL)) { $this->_email=$email; } } public function update(Observer_Exception $e){ $message="時間".date("Y-m-d H:i:s").PHP_EOL; $message.="信息".$e->getMessage().PHP_EOL; $message.="追蹤信息".$e->getTraceAsString().PHP_EOL; $message.="文件".$e->getFile().PHP_EOL; $message.="行號".$e->getLine().PHP_EOL; error_log($message,1,$this->_email); } }
Logging_Exception_Observer.php:code
<?php class Logging_Exception_Observer implements Exception_Observer { protected $_filename="F:/logException.log"; function __construct($filename=null) { if ($filename!==null&&is_string($filename)) { $thvis->_filename=$filename; } } public function update(Observer_Exception $e){ $message="時間".date("Y-m-d H:i:s").PHP_EOL; $message.="信息".$e->getMessage().PHP_EOL; $message.="追蹤信息".$e->getTraceAsString().PHP_EOL; $message.="文件".$e->getFile().PHP_EOL; $message.="行號".$e->getLine().PHP_EOL; error_log($message,3,$this->_filename); } }
設計完全部該有的主體對象和插件,咱們作個小小的測試:
<?php require 'Exception_Observer.php'; require 'Observer_Exception.php'; require 'Logging_Exception_Observer.php'; require 'Emailing_Exception_Observer.php'; Observer_Exception::attach(new Logging_Exception_Observer()); class MyException extends Observer_Exception{ public function test(){ echo 'this is a test'; } public function test1(){ echo "我是自定義的方法處理這個異常"; } } try { throw new MyException("出現異常,記錄一下"); } catch (MyException $e) { echo $e->getMessage(); echo "<ht/>"; } ?>
本實例首先先加載觀察者,其後進行其餘操做。回到上面提出的問題, $_observers 能夠不是靜態變量嗎?答案是不能夠。若是 $_observers 不是靜態變量,加載觀察者的行爲對後續操做沒有影響。static讓全部實例成員共享某個變量。即使類繼承也一樣有效。有興趣的能夠繼續探索下static的神奇做用吧。
本例顯示輸出與通常狀況無異,但不一樣的是已在自定義的文件下生成了相應的日誌。雖然最後實現的功能再簡單不過,不少人甚至能夠用更少的代碼更簡單的方法實現,可是,在實現更加複雜系統的狀況下,觀察者模式給咱們帶來很大方便。