为了实现以观测模式为基础的错误记录句柄
,首先我们注意到作为观测者的FileErrorLogger类和EmailErrorLogger类什么也不能做
。那么
,FileErrorLogger类是如何向一个文件写出错信息,EmailErrorLogger类又如何发送电子邮件的?接下来,让我来看看用来实现观测模式的技术细节,然后,再集中精力来看看该模式的主体――ErrorHandler的细节
。最后,再写一些错误处理函数来调用这个ErrorHandler类。
最后用下面的这一段代码来表示:
//
PHP4
$eh=&getErrorHandlerInstance();
$eh->attach(newEmailErrorLogger(
‘jsweat_php@yahoo.com’));
$eh->attach(newFileErrorLogger(fopen(‘error.log’,’w’)));
set_error_handler(‘observer_error_handler’);
//...later
trigger_error(‘thisisanerror’);
ErrorHandler类是一种单件模式(参考第4章:TheSingletonPattern)。它可以通过函数Attach()来注册各种错误信息观测者,而set_error_handler()函数就是一个指向ErrorHandler类的函数。最后,当一个错误信息被触发后,所有的观测者都会得到通知。
为了使这次观测的操作生效,你的测试必须能证明所有的这些操作(将错误信息写入日志,利用电子邮件发送错误信息)都能得到执行,并且能正常工作。简而言之,让我们来看看一系列简单的测试。(和这个实例有关的其他更多实例,可以在本书附带的源代码中找到)
这里有FileErrorLogger类联合测试的一部分代码:它用来测试当FileErrorlogger类被某个对象实例化时,是否具有向一个文件写日志的能力。
classFileErrorLoggerTestCaseextendsUnitTestCase{
var$_fh;
var$_test_file=‘test.log’;
functionsetup(){
@unlink($this->_test_file);
$this->_fh=fopen($this->_test_file,‘w’);
}
functionTestRequiresFileHandleToInstantiate(){/*...*/}
functionTestWrite(){
$content=‘test’.rand(10,100);
$log=&newFileErrorLogger($this->_fh);
$log->write($content);
$file_contents=file_get_contents($this->_test_file);
$this->assertWantedPattern(‘/’.$content.’$/’,$file_contents);
}
functionTestWriteIsTimeStamped(){/*...*/}
}
在这个测试中,setup()函数创建了一个文件指针,指向一个名为“test.log”的新文件。并且,将该指针保存在变量$_fh中,这个可写的文件指针将作为一个变量传递给FileErrorlogger对象的实例,进行测试。变量$content的值将传递给函数write(),并且,在存储结束后,还将用来被检查$content的值是否确实被正确写入test.log文件中。
(这个测试要求
PHP必须具有向那个新建的test.log中写数据的权限。)
下面的一些代码也许可以帮助FileErrorLogger类通过测试。
classFileErrorLogger{
var$_fh;
functionFileErrorLogger($file_handle){
$this->_fh=$file_handle;
}
functionwrite($msg){
fwrite($this->_fh,date(‘Y-m-dH:i:s:‘).$msg);
}
}
一个类似的测试代码可以使EmailErrorLogger类生效。
classEmailErrorLoggerTestCaseextendsUnitTestCase{
functionTestEmailAddressFirstConstructorParameter(){
$log=&newEmailErrorLogger;
$this->assertErrorPattern(‘/missing.*1/i’);
}
functionTestMail(){
$log=&newEmailErrorLogger(
‘jsweat_php@yahoo.com’);
$log->mail(‘testmessage’);
}
}
接下来,通过这个测试的EmailErrorLogger类的代码如下:
classEmailErrorLogger{
var$_addr;
var$_subject;
functionEmailErrorLogger($addr,
$subject=’ApplicationErrorMessage’){
$this->_addr=$addr;
$this->_subject=$subject;
}
functionmail($msg){
mail($this->_addr
,$this->_subject
,date(‘Y-m-dH:i:s:‘).$msg);
}
}
你是怎样确定EmailErrorLogger类能真正发送电子邮件的呢?是的,你可以打开你的收件箱,看看其中是否有新邮件,就知道了。但是,那就不是一个全自动的测试了。或者说,这个测试就只是伪模式的一个不错的替代方案。(至于如何创建一个控制邮件的类,将作为一个练习留给读者的。详细信息,请参考第6章TheMockObjectPattern或参考FakeMail项目