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:发生错误所在的行。





浙公网安备 33010602011771号