php异常和错误处理

异常和错误处理

  在语言级别上,通常具有许多错误处理模式,但这些模式往往建立在约定俗称的基础上,也就是说这些错误都是预知的。但是在大型程序中,如果每次调用都去逐一检查错误,会使代码变得冗长复杂,到处充斥着if……else,并且严重降低代码的可读性。而且人的因素也是不可信赖的,程序员可能并不会把这些问题当一回事,从而导致业务异常。在这种背景下,就逐渐形成了异常处理机制,或者强迫消除这些问题,或者把问题提交给能解决它的环境。这就把“描述在正常过程中做什么事的代码”和“出了问题怎么办的代码”进行分离。

PHP中的错误处理机制

  PHP里有一套错误处理机制,可以使用set_error_handler接管PHP错误处理,也可以使用trigger_error函数主动抛出一个错误。
  set_error_handler()函数设置用户自定义的错误处理函数。函数用于创建运行期间的用户自己的错误处理方法。它需要先创建一个错误处理函数,然后设置错误级别。语法如下:

set_error_handler(error_function, error_types)

  参数描述如下:
  error_function:规定发生错误时运行的函数。必需。
  error_types:规定在哪个错误报告级别会显示用户定义的错误。可选。默认为”E_ALL”。

提示:如果使用该函数,会完全绕过标准PHP错误处理函数,如果有必要,用户定义的错误处理程序必须终止(die())脚本。

  如果在脚本执行前发生错误,由于在那时自定义程序还没有注册,因此就不会用到这个自定义错误处理程序。这先实现一个自定义的异常异常处理函数,如代码清单1-21所示。
  代码清单1-21 自定义的异常处理函数

<?php
    function customError($errno, $errstr, $errfile, $errline){
        echo '<b>错误代码:<b>[' . $errno . ']' . $errstr . '\r \n';
        echo '错误所在的代码行:' . $errline . ',文件:' . $errfile . '\r \n';
        die();
    }
    set_error_handler('customError', E_ALL | E_STRICT);
    $a = array('o' => 2,4,6,8);
    echo $a[o];

  在这个函数里,可以对错误的详情进行格式化输出,也可以做任何要做的事情,比如判断当前环境和权限给出不同的错误提示,可使用error_log函数将错误记入log文件,还可以细化处理,针对errno的不同进行对应的处理。
  自定义的错误处理函数一定要有这四个输入变量errno,errstr,errline,errfile。
  errno是一组常量,代表错误的等级,同时也有一组整数和其对应,但一般使用其字符串值表示,这样语义更好一点。比如E_WARNING,其二进制掩码为4.,表示警告信息。
  接下来,就是将这个函数作为回调参数传递给set_error_handler。这样就能接管PHP原生的错误处理函数了。要注意的是,这种托管方式并不能托管所有种类的错误,如E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING,以及E_STRICT中的部分。这些错误会以最原始的方式显示,或者不显示。
  set_error_handler函数会接管PHP内置的错误处理,你可以在同一个页面使用restore_error_handler();取消接管。

注意:如果使用自定义的set_error_handler接管PHP的错误处理,先前代码里的错误抑制@将失效,这种错误也会被显示。

  在PHP异常中,异常处理机制是有限的,无法自动抛出异常,必须手动进行,并且内置异常有限。PHP把许多异常看做错误,这样就可以把这些“异常”像错误一样用set_error_handler接管。进而主动抛出异常。代码如下所示:

function customError($errno, $errstr, $errfile, $errline){
    //自定义错误处理时,手动抛出异常
    throw new Exception($level . '|' $errstr);
}
set_error_handler('customError', E_ALL | E_STRICT);
try{
    $a = 5/0;
}catch(Exception $e){
    echo '错误信息:' . $e->getMessage();
}

  这样就能捕获到异常和非致命的错误,可以弥补PHP异常处理机制的部分不足。
  这种“曲折迂回”的处理方式存在的问题就是:必须依靠程序员自己来掌握对异常的处理,对于异常高发区,敏感区,如果程序员处理不好,就会导致前面所提到的业务数据不一致的问题。其优点在于,可以获得程序运行时的上下文信息,以进行针对性的补救。
  fetal error这样的错误虽然捕获不到,也无法在发生此错误后恢复流程处理,但是还是可以使用一些特殊方法对这种错误进行处理的。这需要用到一个函数——register_shutdown_function,此函数会在PHP程序终止或者die时触发一个函数,给PHP来一个短暂的“回光返照”。在PHP4的时代,类不支持析构函数,常用这个函数模拟实现析构函数。实例代码如下:

<?php
class Shutdown{
    public function stop(){
        if (error_get_last()){
            print_r(error_get_last());
        }
        die('Stop');
    }
}
register_shutdown_function(array( new Shutdown(), 'stop'));
$a = new a(); // 将因为致命错误而失败
echo '必须终止';

  可以运行看看效果。对于fetal_error还能做点收尾工作,但是PHP流程的终止是必然的。对于Parse error级别的错误,你只有傻眼了,除了可以修改配置文件php.ini,什么都做不了,修改的内容如下:

log_errors=On
error_log=usr/log/php.log

  这样一旦PHP发生了错误,就会被记入log文件,方便以后查询。
  和exception类似,错误处理也有对应抛出错误的函数,那就是trigger_error函数,如下所示:

<?php
    $divisor=0;
    if ($divisor == 0){
        trigger_error('Cannot divide by zero', E_USER_ERROR);
    }
    echo 'break';

提示:在PHP中,错误和异常是两个不同的概念,这种设计从根本上导致了PHP的异常和其他语言相异。以Java为例,Java中,异常是错误唯一的报告方式。说到底,两者的区别就是对异常和错误的认识不同而产生的。PHP的异常绝大部分必须通过某种办法手动抛出,才能被捕获到,是一种半自动化的异常处理机制。

  无论是错误还是异常,都可以使用handler接管系统已有的处理机制。

展开阅读全文

没有更多推荐了,返回首页