异常信息的捕获对编程测试有着重要的意义,这里结合观察者模式,探索如何处理异常信息。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的神奇做用吧。
本例显示输出与通常状况无异,但不一样的是已在自定义的文件下生成了相应的日志。虽然最后实现的功能再简单不过,不少人甚至能够用更少的代码更简单的方法实现,可是,在实现更加复杂系统的状况下,观察者模式给咱们带来很大方便。