PHP的错误和异常处理
错误处理
错误报告级别
调整错误报告级别
- 可以通过在配置文件php.ini中,修改配置指令error_reporting的值,修改成功后重新启动Web服务器,则每个PHP脚本都可以按调整后的错误报告。下面是修改php.ini配置文件的示例。列出几种为error_reporting指令设置不同级别的值的方式,可以把位运算符[&(与)、|(或)、~(非)]和错误级别常量一起使用。
1 2 3 4 5 6 | ;可以抛出任何非注意的错误,默认值 error_reporting = E_ALL &~ E_NOTICE ;只考虑致命的运行时错误、解析错误和核心错误 error_reporting = E_ERROE | E_PARSE | E_CORE_ERROR ;报告除用户导致的错误之外的所有错误 error_reporting = E_ALL &~(E_USER_ERROR | E_USER_WARNING |E_USER_NOTICE) |
- 或者在php脚本中使用error_reporting()函数,基于各个脚本来调整这种行为。这个函数用于确定php应该在特定的页面内报告哪些类型的错误。该函数获取一个数字或错误级别常量作为参数。
1 2 3 | error_reporting(0); //设置为0会完全关闭错误报告 error_reporting(E_ALL); //将会向PHP报告发生的每个错误 error_reporting(E_ALL & ~ E_NOTICE); //可以抛出任何非注意的错误报告 |
使用trigger_error()函数来替代die()
自定义错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php error_reporting (0); //屏蔽程序中的错误 /** 定义Error_Handler函数,作为set_error_handler()函数的第一个参数"回调" @param int $error_level 错误级别 @param string $error_message 错误信息 @param string $file 错误所在文件 @param int $lin 错误所在行数 */ function error_handler( $error_level , $error_message , $file , $line ) { $EXIT = FALSE; switch ( $error_level ) { //提醒级别 case E_NOTICE: case E_USER_NOTICE; $error_type = 'Notice' ; break ; //警告级别 case E_WARNING: case E_USER_WARNING: $error_type = 'Warning' ; break ; //错误级别 case E_ERROR: case E_USER_ERROR: $error_type = 'Fatal Error' ; $EXIT = TRUE; break ; //其他末知错误 default : $error_type = 'Unknown' ; $EXIT = TRUE; break ; } //直接打印错误信息, 也可以写文件,写数据库,反正错误信息都在这,任你发落 printf ( "<font color='#FF0000'><b>%s</b></font>: %s in <b>%s</b> on line <b>%d</b><br>\n" , $error_type , $error_message , $file , $line ); //如果错误影响到程序的正常执行,跳转到友好的错误提示页面 if (TRUE == $EXIT ) { echo '<script>location = "err.html"; </script>' ; } } //这个才是关键点, 把错误的处理交给error_handler() set_error_handler( 'error_handler' ); //使用末定义的变量要报 notice 的 echo $novar ; //除以0要报警告的 echo 3/0; //自定义一个错误 trigger_error( 'Trigger a fatal error' , E_USER_ERROR); |
- 系统直接报Fital Error这个方法是捕获不到的,遇到这种错误是必须解决的,所以系统会直接终止程序运行。
- E_ERROR、E_PARSE、E_CORE_ERROR、ERROR_WARNING/E_COMPILE_ERROR、ERROR_COMPILE_WARNING是不会被这个句柄处理的,也就是会用原始的方式显示出来。不过出现这些错误都是编译或PHP内核错误,在通常情况下不会发生。
- 使用set_error_handler()后,error_reporting()将会失效。也就是所有的错误都会交给自定义的函数处理。
写错误日志
如果使用自己指定的文件记录错误日志,一定要确保将这个文件存放在文档目录之外,以减少遭到攻击的可能。并且该文件一定要让PHP脚本的执行用户具有写权限。假设在linux操作系统中,将/usr/local/目录下的config文件作为错误日志文件,并设置Web服务器进程用户具有写的权限。然后在php的配置文件中,将error_log指令的值设置为这个错误日志文件的绝对路径。需要对php.ini中的配置指令做如下修改:
1 2 3 4 5 6 7 8 9 10 | ;将会向php报告发生的每个错误 error_reporting = E_ALL ;不显示满足上条指令所定义规则的所有错误报告 display_errors = Off ;决定日志语句记录的位置 log_errors = On ;设置每个日志想的最大长度 log_errors_max_len = 1024 ;指定产生的错误报告写入的日志文件位置 error_log = /usr/local/error.log |
还可以使用php中的error_log()函数,送出一个用户自定义的错误信息。
1 | bool error_log(stringmessage[, int message_type[,string destination[,string extra_headers]]]) |
第一个参数:必选项,即为要送出的错误信息。
第二个参数:为整数值,0表示送到操作系统的日志中;1则使用PHP的Mail()函数,发送信息到某Email地址处,第四个参数也会用到;2则将错误信息送到TCP服务器中,此时第三个参数destination表示目的地ip及Port;3则将信息存到文件destination中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php if(!Ora_Logon($username, $password)){ //将错误消息写入到操作系统日志中 error_log("Oracle数据库不可用!", 0); } if(!($foo=allocate_new_foo()){ //发送到管理员邮箱中 error_log("出现大麻烦了!", 1, "webmaster@www.mydomain.com"); } //发送到本机对应5000端口的服务器中 error_log("搞砸了!", 2, "localhost:5000"); //发送到指定的文件中 error_log("搞砸了!", 3, "/usr/local/errors.log"); |
2、错误信息记录到操作系统的日志里
1 2 3 4 5 6 7 8 9 10 | ;将会向php报告发生的每个错误 error_reporting = E_ALL ;不显示满足上条指令所定义规则的所有错误报告 display_errors = Off ;决定日志语句记录的位置 log_erros = On ;设置每个日志项的最大长度 log_errors_max_len = 1024 ;指定产生的错误报告写入操作系统的日志里 error_log = syslog |
php还允许想系统syslog中发送定制的消息,php为这个特性提供了需要一起使用的4个专用函数。
- define_syslog_variables()
使用openlog()、syslog()及closelog()三个函数之前必须先调用该函数,因为在调用该函数时,他会根据现在的系统环境为下面三个函数初使用化一些必需的常量。
- openlog()
打开一个和当前系统中日志器的连接,为向系统插入日志消息做好准备。并将提供的第一个字符串参数插入到每个日志消息中,该函数还需要指定两个将在日志上下文使用的参数。
- syslog()
该函数向系统日志中发送一个定制消息。需要两个必选参数,第个参数通过指定一个常量定制消息的优先级。第二个参数则是像系统日志中发送定制的消息,需要提供一个消息字符串,也可以是php引擎在运行时提供的错误字符串。
- closelog()
1 2 3 4 5 6 7 | <?php define_syslog_variables(); openlog( "PHP5" , LOG_PID , LOG_USER); syslog(LOG_WARNING, "警告报告向syslog中发送的演示,警告时间:" . date ( "Y/m/d H:i:s" )); closelog (); |
异常处理
异常处理实现
在php中,异常必须手动抛出。throw关键字将触发异常处理机制,他是一个语言结构,而不是一个函数,但必须给它传递一个对象作为值。如果在try语句中游艺场对象被抛出,改代码块不会再继续向下执行,而直接转到catch中执行。并传给catch代码块一个对象,也可以理解为被catch代码块不活的对象,其实就是导致异常常被throw语句抛出的对象。
扩展php那只的异常处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php /* 自定义的一个异常处理类 ,但必须是扩展内异常处理类的子类 */ class MyException extends Exception{ //重定义构造器是第一个参数message变为必须被指定的属性 public function __construct( $message , $code =0){ //可以在这里定义一些自己的代码 //建议同时调用parent::construct()来检查所有的变量是否已被赋值 parent::__construct( $message , $code ); } //重写父类方法,自定义字符串输出的样式 public function __toString(){ return __CLASS__ . ":[" . $this ->code. "]" . $this ->message. "<br/>" ; } //为这个异常自定义一个处理方法 public function customFunction(){ echo "按自定义的方法处理出现的这个类型的异常<br/>" ; } } try { $error = "允许抛出这个错误" ; throw new MyException( $error ); echo 'Never executed' ; } catch (MyException $e ) { echo '捕获异常:' . $e ; $e ->customFunction(); } echo "你好!" ; |
捕获多个异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <?php /* 自定义的一个异常处理类,但必须是扩展内异常处理类的子类 */ class MyException extends Exception{ //重定义构造器使第一个参数 message 变为必须被指定的属性 public function __construct( $message , $code =0){ //可以在这里定义一些自己的代码 //建议同时调用 parent::construct()来检查所有的变量是否已被赋值 parent::__construct( $message , $code ); } //重写父类中继承过来的方法,自定义字符串输出的样式 public function __toString() { return __CLASS__ . ":[" . $this ->code. "]:" . $this ->message. "<br>" ; } //为这个异常自定义一个处理方法 public function customFunction() { echo "按自定义的方法处理出现的这个类型的异常" ; } } /* 创建一个用于测试自定义扩展的异常类MyException */ class TestException { public $var ; //用来判断对象是否创建成功的成员属性 function __construct( $value =0) { //通过构造方法的传值决定抛出的异常 switch ( $value ){ //对传入的值进行选择性的判断 case 1: //传入参数1,则抛出自定义的异常对象 throw new MyException( "传入的值“1” 是一个无效的参数" , 5); break ; case 2: //传入参数2,则抛出PHP内置的异常对象 throw new Exception( "传入的值“2”不允许作为一个参数" , 6); break ; default : //传入参数合法,则不抛出异常 $this -> var = $value ; break ; //为对象中的成员属性赋值 } } } /* 示例1,在没有异常时,程序正常执行,try中的代码全部执行并不会执行任何catch区块 */ try { $testObj = new TestException(); //使用默认参数创建异常的测试类对象 echo "***********<br>" ; //没有抛出异常这条语句就会正常执行 } catch (MyException $e ){ //捕获用户自定义的异常区块 echo "捕获自定义的异常:$e <br>" ; //按自定义的方式输出异常消息 $e ->customFunction(); //可以调用自定义的异常处理方法 } catch (Exception $e ) { //捕获PHP内置的异常处理类的对象 echo "捕获默认的异常:" . $e ->getMessage(). "<br>" ; //输出异常消息 } var_dump( $testObj ); //判断对象是否创建成功,如果没有任何异常,则创建成功 /* 示例2,抛出自定义的异常,并通过自定义的异常处理类捕获这个异常并处理 */ try { $testObj1 = new TestException(1); //传1时,抛出自定义异常 echo "***********<br>" ; //这个语句不会被执行 } catch (MyException $e ){ //这个catch区块中的代码将被执行 echo "捕获自定义的异常:$e <br>" ; $e ->customFunction(); } catch (Exception $e ) { //这个catch区块不会执行 echo "捕获默认的异常:" . $e ->getMessage(). "<br>" ; } var_dump( $testObj1 ); //有异常产生,这个对象没有创建成功 /* 示例2,抛出内置的异常,并通过自定义的异常处理类捕获这个异常并处理 */ try { $testObj2 = new TestException(2); //传入2时,抛出内置异常 echo "***********<br>" ; //这个语句不会被执行 } catch (MyException $e ){ //这个catch区块不会执行 echo "捕获自定义的异常:$e <br>" ; $e ->customFunction(); } catch (Exception $e ) { //这个catch区块中的代码将被执行 echo "捕获默认的异常:" . $e ->getMessage(). "<br>" ; } var_dump( $testObj2 ); //有异常产生,这个对象没有创建成功 |
错误查询
error_get_last():
函数获取最后发生的错误。
该函数以数组的形式返回最后发生的错误。
返回的数组包含 4 个键和值:
- type:错误类型。
- message:错误消息。
- file:发生错误所在的文件。
- line:发生错误所在的行。