php错误/异常处理

写在前面

  主要内容:错误类型,调试方法,自定义错误处理函数set_error_handler(),错误日志处理,异常处理。

错误类型

  运行PHP脚本时,PHP解析器会尽其所能地报告它遇到的问题。在PHP中错误报告的处理行为,都是通过PHP的配置文件php.ini中有关的配置指令确定的。另外PHP的错误报告有很多种级别,可以根据不同的错误报告级别提供对应的调试方法。下表列出了php中大多数的错误报告级别:这里我只列举了一部分(具体所有常量参见php手册错误处理预定义常量)

常量 说明 备注
1 E_ERROR (integer) 致命的运行时错误。这类错误一般是不可恢复的情况,例如内存分配导致的问题。后果是导致脚本终止不再继续运行。
2 E_WARNING (integer) 运行时警告 (非致命错误)。仅给出提示信息,但是脚本不会终止运行。
4 E_PARSE (integer) 编译时语法解析错误。解析错误仅仅由分析器产生。
8 E_NOTICE (integer) 运行时通知。表示脚本遇到可能会表现为错误的情况,但是在可以正常运行的脚本里面也可能会有类似的通知。
16 E_CORE_ERROR (integer) 在PHP初始化启动过程中发生的致命错误。该错误类似 E_ERROR,但是是由PHP引擎核心产生的。 since PHP 4
32 E_CORE_WARNING (integer) PHP初始化启动过程中发生的警告 (非致命错误) 。类似 E_WARNING,但是是由PHP引擎核心产生的。 since PHP 4
64 E_COMPILE_ERROR (integer) 致命编译时错误。类似E_ERROR, 但是是由Zend脚本引擎产生的。 since PHP 4
128 E_COMPILE_WARNING (integer) 编译时警告 (非致命错误)。类似 E_WARNING,但是是由Zend脚本引擎产生的。 since PHP 4
30719 E_ALL (integer) E_STRICT出外的所有错误和警告信息。 30719 in PHP 5.3.x, 6143 in PHP 5.2.x, 2047 previously
设置出错时候是否输出错误消息:
1. php.ini文件中的display_errors参数(on-开启,off-关闭)
2. 运行中动态设置,ini_set(‘display_errors’, true)
在程序开发阶段打开错误消息输出,方便调试;线上环境关闭,防止泄露服务器相关的信息,使服务器变得不安全。
设置出错时错误报告的级别:
1. php.ini文件中的error_reporting参数,error_reporting=E_ALL & ~E_NOTICE
2. 运行中动态设置,error_reporting(E_ALL & ~E_NOTICE),

php错误日志

  产品投入运营之后,线上环境就会关闭错误消息输出,以免因为这些错误所透露的路径、数据库连接、数据表等信息而遭到黑客攻击。那么就需要错误日志来记录程序运行中产生的错误信息。
  1. 开启php错误日志记录,在php.ini中设置log_errors参数on,那么在程序中产生的php错误就会记录到服务器的错误日志之中。
  2. 设置了error_log参数,就可将错误日志记录到指定路径的文件之中
  3. php中的error_log()函数,可以送出用户自定义的消息到日志文件,邮件,发送到其他服务器或者到操作系统的日志。

set_error_handler()

  set_error_handler(PHP 4 >= 4.0.1, PHP 5, PHP 7) — 设置一个用户定义的错误处理函数
  函数原型:
  mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )
  1. 设置用户自定义函数error_handler处理脚本中的错误,用户自定义函数原型:
    handler ( int $errno , string $errstr [, string $errfile [, int $errline [, array $errcontext ]]] )
    - 错误码errno和描述错误的errstr是必选参数,另外有可能提供三个可选参数:发生错误的文件名errfile、发生错误的行号errline 以及发生错误的上下文errcontext(一个指向错误发生时活动符号表的 array)。
    - 如果函数返回 FALSE,标准错误处理处理程序将会继续调用。
    - 如果错误发生在脚本执行之前,将不会调用自定义的错误处理程序因为它尚未在那时注册。
    - 自定义函数处理完成之后程序会继续执行。
  例子:

//先定义一个函数,也可以定义在其他的文件中,再用require()调用  
function myErrorHandler($errno, $errstr, $errfile, $errline)  
{  
    //为了安全起见,不暴露出真实物理路径,下面两行过滤实际路径  
    $errfile=str_replace(getcwd(),"",$errfile);  
    $errstr=str_replace(getcwd(),"",$errstr);  

    switch ($errno) {  
    case E_USER_ERROR:   
         echo "<b>My ERROR</b> [$errno] $errstr<br />\n";  
        echo "  Fatal error on line $errline in file $errfile";  
        echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";  
        echo "Aborting...<br />\n";  
        exit(1);  
        break;  
    case E_USER_WARNING:  
        echo "<b>My WARNING</b> [$errno] $errstr<br />\n";  
        break;    
    case E_USER_NOTICE:  
        echo "<b>My NOTICE</b> [$errno] $errstr<br />\n";  
        break;  
    default:  
        echo "Unknown error type: [$errno] $errstr<br />\n";  
        break;  
    }  
/* Don't execute PHP internal error handler */  
return true;  
}  

  2. error_types 此参数能够用于屏蔽 error_handler 的触发,即此参数的设置是产生错误时出发error_handler函数的错误级别。 如果没有该掩码(默认值是E_ALL | E_STRICT),也就是说无论 error_reporting 是如何设置的, error_handler 都会在每个错误发生时被调用。
  3. 如果之前有定义过错误处理程序,则返回该程序名称的 string;如果是内置的错误处理程序,则返回 NULL。 如果你指定了一个无效的回调函数,同样会返回 NULL。 如果之前的错误处理程序是一个类的方法,此函数会返回一个带类和方法名的索引数组(indexed array)。
  三种用法:

class CallbackClass {
   function CallbackFunction() {
       // refers to $this
       }
   function StaticFunction() {
       // doesn't refer to $this
    }
}

function NonClassFunction($errno, $errstr, $errfile, $errline) {
}

1: set_error_handler('NonClassFunction');  // 直接转到一个普通的函数 NonClassFunction

2: set_error_handler(array('CallbackClass', 'StaticFunction')); // 转到 CallbackClass 类下的静方法 StaticFunction

3: $o =& new CallbackClass();
set_error_handler(array($o, 'CallbackFunction'));  // 转到类的构造函数,其实本质上跟下面的第四条一样。

4: $o = new CallbackClass();
// The following may also prove useful:
class CallbackClass {
    function CallbackClass() {
       set_error_handler(array(&$this, 'CallbackFunction')); // the & is important
   }
   function CallbackFunction() {
       // refers to $this
   }
}  

try catch

  异常(Exception)处理用于在指定的错误发生时改变脚本的正常流程,是PHP 5中的一个新的重要特性。异常处理是一种可扩展、易维护的错误处理统一机制,并提供了一种新的面向对象的错误处理方式。
  实例:

try {
    $error = 'Always throw this error';
    throw new Exception($error);      //创建一个异常对象,通过throw语句抛出
    echo 'Never executed';            //从这里开始,try代码块内的代码将不会再被执行
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";  //输出捕获的异常消息
}
echo 'Hello World';                    //程序没有崩溃继续向下执行

  1. 在某些编程语言中,例如Java,在出现异常时将自动抛出异常。而在PHP中,异常必须手动抛出
  2. 扩展内置Exception类

class Exception {
    protected $message = 'Unknown exception';              //异常信息
    protected $code = 0;                              //用户自定义异常代码
    protected $file;                                   //发生异常的文件名
    protected $line;                                  //发生异常的代码行号
    public function __construct($message = "", $code = 0, Exception $previous = null) {}    //构造方法
    /*
    *其中还有一些其他的方法,根据版本不同
    */
    final function getMessage(){}                        //返回异常信息
    final function getCode(){}                           //返回异常代码
    final function getFile(){}                            //返回发生异常的文件名
    final function getLine(){}                            //返回发生异常的代码行号
    final function getTrace(){}                           //backtrace() 数组
    final function getTraceAsString(){}                    //已格成化成字符串的 getTrace() 信息
    /* 可重载的方法 */
    function __toString(){}                             //可输出的字符串
    }  

  扩展的时候注意构造方法和__toString(){}方法,另外还可以加入自己的自定义方法。

参考资料

  http://jingyan.baidu.com/article/046a7b3ed5e233f9c37fa969.html
  http://www.cnblogs.com/laojie4321/p/4187620.html
  http://justcoding.iteye.com/blog/848711