PHP10 错误和异常处理

时间:2022-08-08 12:21:41

学习要点

  • 修改错误报告级别
  • 写错误日志
  • 异常处理实现
  • 自定义异常
  • 捕获多路异常

 

错误处理

定义

  • 错误:开发过程中的失误、用户操作引起的错误。
  • 错误产生原因
  1. 语法错误:开发环境提示,未修正则脚本无法运行。
  2. 运行时错误:脚本无法正确运行。例如双引号字符串对变量的解析。
  3. 逻辑错误:常见的逻辑运算错误,循环条件设置错误等等。

错误报告级别

1、WAMP作为开发环境,在php.ini配置文件中,有两个参数设置:

  • display_errors = on

    注释:PHP解析器将会输出错误报告的功能。如果是产品正式发布部署,需要在PHP服务器上把此项值值为off。

  • error_reporting = E_ALL

    注释:PHP解析器将输出每个错误。

2、PHP的错误报告级别:

常量

描述

1

E_ERROR

Fatal run-time errors. Errors that can not be recovered from. Execution of the script is halted

2

E_WARNING

Non-fatal run-time errors. Execution of the script is not halted

4

E_PARSE

Compile-time parse errors. Parse errors should only be generated by the parser

8

E_NOTICE

Run-time notices. The script found something that might be an error, but could also happen when running a script normally

16

E_CORE_ERROR

Fatal errors at PHP startup. This is like an E_ERROR in the PHP core

32

E_CORE_WARNING

Non-fatal errors at PHP startup. This is like an E_WARNING in the PHP core

64

E_COMPILE_ERROR

Fatal compile-time errors. This is like an E_ERROR generated by the Zend Scripting Engine

128

E_COMPILE_WARNING

Non-fatal compile-time errors. This is like an E_WARNING generated by the Zend Scripting Engine

256

E_USER_ERROR

Fatal user-generated error. This is like an E_ERROR set by the programmer using the PHP function trigger_error()

512

E_USER_WARNING

Non-fatal user-generated warning. This is like an E_WARNING set by the programmer using the PHP function trigger_error()

1024

E_USER_NOTICE

User-generated notice. This is like an E_NOTICE set by the programmer using the PHP function trigger_error()

2048

E_STRICT

Run-time notices. PHP suggest changes to your code to help interoperability and compatibility of the code

4096

E_RECOVERABLE_ERROR

Catchable fatal error. This is like an E_ERROR but can be caught by a user defined handle (see also set_error_handler())

8191

E_ALL

All errors and warnings, except level E_STRICT (E_STRICT will be part of E_ALL as of PHP 6.0)

3、开启错误报告

处理在php.ini文件中配置,如果对服务器权限不够,可以采用ini_set()函数设置:

例如:

ini_set(‘display_errors’,1);

  

调整错误报告级别

1、在php.ini中修改配置指令error_reporting的值

默认值:

error_reporting = E_ALL

修改示例1(结合位运算符&,|,~):除运行时注意消息外的全部错误报告

error_reporting = E_ALL&~E-NOTICE; 

修改示例2:只考虑运行时错误、解析错误、核心错误

error_reporting = E_ERROR | E_PARSE | E_CORE_ERROR

  

2、在脚本中使用error_reporting()函数

  权限不够,或者需要个性化页面错误报告,采用该函数。

error_reporting(0);     //完全关闭错误报告

error_reporting(E_ALL);    //报告任何错误

error_reporting(E_ALL&~E_NOTICE);    //报告除注意外的任何错误

  

示例:

/* 开启php.ini中的display_errors指令*/

       ini_set ( 'display_errors', 1);

       /* 通过error_reporting()函数设置在本脚本中,输出所有级别的错误报告 */

       error_reporting ( E_ALL );

//error_reporting ( E_ALL &~(E_WARNING|E_NOTICE));     

       /* “注意(notice)”的报告,不会阻止脚本的执行,并且可能不一定是一个问题 */

       getType ( $var ); // 调用函数时提供的参数变量没有在之前声明    

       /* “警告(warning)”的报告,指示一个问题,但是不会阻止脚本的执行 */

       getType (); // 调用函数时没有提供必要的参数     

       /* “错误(error)”的报告,它会终止程序,脚本不会再向下执行 */

    get_Type (); // 调用一个没有被定义的函数

  

使用trigger_error()函数代替die()函数

die()等同于exit(),会退出程序。而trigger_error()可以生成一个用户警告来代替退出程序。

示例代码:

//die("程序运行结束!");

trigger_error("there is a bugbugbug!",E_USER_WARNING);

echo "这里是php文件尾巴";

  

自定义错误处理

1、需要自定义错误信息的情形

    • 记录错误信息
    • 屏蔽错误信息
    • 错误统一输出页面处理或者同一页面位置输出错误信息
    • 调试

2、如何自定义错误处理

用户自定义错误处理函数:set_error_handler()

语法格式:

mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

  

参数说明:

error_handler:

handler ( int $errno , string $errstr [, string $errfile [, int $errline [, array $errcontext ]]] )  //四个参数含义:错误级别、错误信息、错误所在文件,错误所在文件第几行

error_types:

错误报告级别。默认E_ALL。

示例代码:

// 屏蔽所有错误报告

error_reporting ( 0 );

function error_handler($error_level, $error_message, $file, $line) {

   $EXIT = false;

   $error_type='';

   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';

         break;

      //未知错误

      default:

         $error_type = 'Unknown';

         $EXIT=true;

         break;

   }

   //打印错误信息,可以自定义错误格式

   printf("%s,%s,%s,%d",$error_type,$error_message,$file,$line);

   if(true==$EXIT){

      echo '<script>location="error.php";</script>';

   }

}

set_error_handler('error_handler');

//echo $novar;

echo 3/0;

  

注意:

1、set_error_handler()不处理以下错误报告:E_ERR0R、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING。不处理不等于不显示错误信息,它不会按照用户设定格式显示。

2、除了第1条中列出的错误,在使用了set_error_handler()函数后,所有的错误都交给用户处理。

上机练习1:自定义错误处理

1、  set_error_handler()函数的用法

2、  自定义回调函数

3、  错误报告格式:

写错误日志

PHP项目部署运行后,一般display_errors = off。程序日常运行的错误信息是需要记录下来,作为运维参考,如何处理?有两种记录日志的方式:

1、使用指定的文件记录错误报告日志

php.ini配置

error_reporting = E_ALL

display_errors = off

log_errors=on

log_errors_max_len = 1024

error_log = "d:/wamp/logs/php_error.log"

error_log()函数

//写入操作系统日志 (需要php.ini中设置error_log=syslog)

error_log("error message",0);

//发送到电子邮件(需要邮件服务器)

error_log("error message",1,"2083967667@qq.com");

//发送到某个ip的某个端口

error_log("error message",2,"localhost:5000");

//写入到某个路径文件中

error_log("error message",3,"er.log");

  

2、错误信息记录到操作系统日志中

php.ini配置

error_reporting = E_ALL

display_errors = off

log_errors=on

log_errors_max_len = 1024

error_log = syslog

使用syslog向系统发送订制消息

//php5.3开始,已经废除相关函数

define_syslog_variables();

……

  

异常处理

定义

Exception:在程序执行过程中出现的一个例外或是一个事件,它中断了正常指令的运行,跳转到其他程序模块继续执行。

简单异常处理

1、语法结构

try{

//需要捕获异常的代码块

}catch (Exception $ex1){

//处理异常

} finally {

//始终被执行的代码

}

  

2、示例代码

try {

   $number = 100;

   $div = 0;

   if ($div == 0) {

      throw new Exception ( "除数不能为0" );

   }

   $result=$number/$div;

   echo '计算结果'.$result;

} catch ( Exception $e ) {

   echo '程序异常:'.$e->getMessage();

}finally {

   echo '<br>finally代码始终执行';

}

echo '<br>程序继续执行';

  

自定义异常处理类

1、内置Exception类结构

class Exception {

   protected $message = 'Unknown exception'; // 异常信息

   protected $code = 0; // 用户自定义异常代码

   protected $file; // 发生异常的文件名

   protected $line; // 发生异常的代码行号

   function __construct($message = null, $code = 0);

   final function getMessage(); // 返回异常信息

   final function getCode(); // 返回异常代码

   final function getFile(); // 返回发生异常的文件名

   final function getLine(); // 返回发生异常的代码行号

   final function getTrace(); // backtrace() 数组

   final function getTraceAsString(); // 已格成化成字符串的 getTrace() 信息

   /* 可重载的方法 */

   function __toString(); // 可输出的字符串

}

  

2、自定义异常处理类

/* 自定义异常处理类 */

class MyException extends Exception {

   // 重写构造函数

   public function __construct($message, $code = 0) {

      parent::__construct ( $message, $code );

   }

   /*重写父类__toString魔术方法*/

   public function __toString() {

      return __CLASS__ . ":[" . $this->code . "]:" . $this->message . "<br>";

   }

   /*自定义异常方法*/

   public function customFunction() {

      echo "按自定义的方法处理出现的这个类型的异常<br>";

   }

}

try {

   $error = '允许抛出这个错误';

   throw new MyException ( $error );

   echo '出现异常,不被执行的代码.....';

} catch ( MyException $e ) {

   echo '捕获异常: ' . $e;

   $e->customFunction ();

}

echo '程序继续执行......';

  

上机练习2:自定义异常处理

多路异常捕获

class MyException extends Exception {

   public function __construct($message, $code = 0) {

      parent::__construct ( $message, $code );

   }

   public function __toString() {

      return __CLASS__ . ":[" . $this->code . "]:" . $this->message . "<br>";

   }

   public function customFunction() {

      echo "按自定义的方法处理出现的这个类型的异常";

   }

}

class TestException {

   public $var;

   function __construct($value = 0) {

      switch ($value) {

         case 1 :

            throw new MyException ( "传入的值“1” 是一个无效的参数", 5 );

            break;

         case 2 :

            throw new Exception ( "传入的值“2”不允许作为一个参数", 6 );

            break;

         default :

            $this->var = $value;

            break;

      }

   }

}

// 示例1,在没有异常时,程序正常执行,try中的代码全部执行并不会执行任何catch区块

$testObj=null;

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,抛出自定义的异常,并通过自定义的异常处理类捕获这个异常并处理

$testObj1=null;

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,抛出内置的异常,并通过自定义的异常处理类捕获这个异常并处理

$testObj2=null;

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 ); // 有异常产生,这个对象没有创建成功