使用觀察者模式處理異常資訊
異常資訊的捕獲對編程測試有著重要的意義,這裡結合觀察者模式,探索如何處理異常資訊。
關於觀察者模式,如果還沒有接觸過的話,部落格園有很多優秀的博友做了詳細的 解釋。筆者覺得,所謂觀察者模式,必須有兩個重要組成部分:一個主題對象,多個觀察者。在使用的時候,我們可以將觀察者像插頭一樣插到主題對象這個插座上,利用主題對象完成相應功能。
既然觀察者要作為插頭,必須要有一個統一的口徑才能插到相同的插座上,因而先定義一個介面,Exception_Observer.php:
php /** * 定義的規範 */interface Exception_Observer{ public function update(Observer_Exception $e);} ?>
相對於眾多觀察者,我們首先應該關注唯一的主題對象,Observer_Exception.php:
phpclass 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()用來通知所有觀察者對象。
這裡需要注意 $observer->update($this); 裡面 $this 的用法,很多初學者會感到“原來 $this 也可以這麼用啊”。
一個小問題: $_observers 不是靜態變數可不可以? 這個問題我們後面回答。
定義兩個觀察者,原則上實現介面所定義的功能。
Email_Exception_Observer.php:
class Emailing_Exception_Observer implements Exception_Observer{ protected $_email="[email protected]"; 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:
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 ""; }?>
本執行個體首先先載入觀察者,其後進行其他動作。回到上面提出的問題, $_observers 可以不是靜態變數嗎?答案是不可以。如果 $_observers 不是靜態變數,載入觀察者的行為對後續操作沒有影響。static讓所有執行個體成員共用某個變數。即便類繼承也同樣有效。有興趣的可以繼續探索下static的神奇作用吧。
本例顯示輸出與一般情況無異,但不同的是已在自訂的檔案下產生了相應的日誌。雖然最後實現的功能再簡單不過,很多人甚至可以用更少的代碼更簡單的方法實現,但是,在實現更加複雜系統的情況下,觀察者模式給我們帶來很大方便。