php_study日记:异常处理
php_study日记:异常处理
2011年12月21日
##异常处理
尽管我们写出了整洁、设计良好的到吗,但在程序运行中仍可能有各种各样的意外出现,当一个程序在运行过程中出现意外时,如除0溢出、数组越界、文件找不到等的异常事件,将阻止程序的正常运行,因此在设计程序时,要充分考虑容错性,估计到可能会发生的各种异常情况并做出相应的处理,以便程序可以稳健地运行。
>以往的异常处理方法
1.PHP.ini将能够显示的错误类型。
2.PHP.ini中error_reporting控制输出到用户端的消息种类。以下几种是php.ini中推荐的配置。
error_reporting = E_ALL; 表示输出所有的信息
error_reporting = E_ALL&~E_NOTICE; 表示输出所有的错误,除了提示。
error_reportin = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE _ERROR : 表示输出所有的ERROR信息。
3.在php.ini中,display_errors可以设置是否将以上设置的错误信息输出到用户端
display_errors=On 输出到用户端(调试代码的时候,打开这项非常的方便)
display_errors=OFF 消息将不会输出到用户端(最终发布给用户时记得改成off)
注意:
在PHP中,对于错误处理的要求是非常宽松的。PHP系统会尽量让程序运行下去,除非遇到致命错误。
除了在php.ini文件中可以调整错误消息的显示级别外,在PHP代码中也可以自定义消息的显示级别。PHP提供了函数error_reporting()来实现本程序中自定义消息显示级别的功能。
函数语法:int error_reporting([int level])
函数说明:使用这个函数可以定义当前PHP页面中错误消息的显示级别。参数level使用了二进制掩码组合的防方式,具体组合方式查表。
>使用die()来终止程序运行
在以往的程序开发过程中,最常见的异常处理办法是程序出现异常就停止执行,使用die()来终止,使当前程序退出。
大新程序项目一般将基础类单独存储在一个文件夹中,每个类单独存储为一个PHP文件,以类名为PHP文件命名。
假设在网站的mail_class目录下为基类库存储文件,该目录下有一stmp.php文件是提供SMTP功能的基类或者接口程序,并有其他一些以类名为文件名的子类文件:normal.php(普通邮件通过mail()函数发送)、auth.php(以需要验证发信人身份的第三方SMTP服务器发送邮件)、MIME.php(发送复杂的图文邮件)等。
Dir . "/" . $smtp . ".php";
if (!file_exists($path))
{
die("Cannot find " . $path . ".\n");
}
require_once $path;
if(!class_exists($smtp))
{
die("class". $smtp . "does not exist .\n");
}
$ret = new $smtp();
if (!($ret instanceof SMTP))
{
die($smtp . " is not a SMTP class .\n");
}
return $ret;
}
}
$smtp = new SMTPManager();
$smtp->GetObject("normal");
?>
在例子中,如果我们尝试寻找类的操作失败,脚本执行将会终止,这体现了代码的安全性。但这段代码不灵活,没有足够的弹性,事实上有时候我们并不希望在找不到想要的类文件时就马上停止执行程序,也许我们有一个默认的命令让程序继续执行。
>使用trigger_error()显示自定义警告信息。
在高于4.01的PHP各版本中提供了trigger_error函数,用以提供自定义警告,在处理错误上会更具优秀,对于客户程序员来说更易于处理错误。
函数语法:bool trigger_error(string $error_msg[,int $error_type])
函数说明:该函数用来提供用户自定义级别的警告、提示、错误信息,trigger_error()接受一个错误信息$error_msg和一个常量$error_type作为参数,可以使用的$error_type常量有3个:E_USER_ERROR(致命错误)、E_USER_WARNING(警告级别非致命错误)、E_USER_NOTICE(提示信息)。
Dir . "/" . $smtp . ".php";
if (!file_exists($path))
{
trigger_error("Cannot find " . $path . ".\n",E_USER_ERROR);
}
require_once $path;
if(!class_exists($smtp))
{
trigger_error("class". $smtp . "does not exist .\n",E_USER_ERROR);
}
$ret = new $smtp();
if (!($ret instanceof SMTP))
{
trigger_error($smtp . " is not a SMTP class .\n",E_USER_ERROR);
}
return $ret;
}
}
function ErrorHandler($errnum,$errmsg,$file,$line)
{
if($errnum == E_USER_ERROR)
{
echo "ERROR:$errmsg\n
";
echo "FILE:$file\n
";
echo "LINE:$line\n
";
exit();
}
}
$handler = set_error_handler('ErrorHandler');
$smtp = new SMTPManager();
$smtp->GetObject("auth");
?>
在本例中,为了处理异常,使用了set_error_handler()自定义处理函数来接收trigger_error()函数抛出来的错误。set_error_handler()接受一个函数名作为参数。如果出发了一个错误,用作参数的这个函数就会被调用来处理错误。此函数需要传入4个参数:错误标志、错误信息、出错文件、出错处的行数。我们还可以将一组数组传递给set_error_handler(),数组中的第一个元素必须是错误处理器将调用的对象,第二个元素时错误处理函数的名称。我们这个错误处理器设计的很简单,还可以改进,如增加记录出错信息,输出debug数据等。但仍然是一个很粗糙的错误处理途径,只能限于已经考虑到的出错情况,如扑捉一个E_USER_ERROR错误,或许我们希望不使用exit()和die()来中止脚本执行,但如果这样做的话,可能会引起一些很微妙的bug,本来应该中止的程序却继续执行了。
>随时判断错误标识
##通过返回值进行处理的方法确实有效,意味着我们可以根据环境来处理多个错误,不一定在第一个错误发生时就马上停止程序的执行,但也有许多不足之处:
#程序复杂
#可靠性差
#返回信息有限
#返回代码标准化困难
使用"false"这样的错误标志的好处是直观,但是明显给出的信息量不够,我们无法得知到底是在哪一个环节上出现错误而导致返回false,于是我们增设一个error_str属性,这样产生错误后能输出更详细的出错信息。
error_str = get_class($this).