PHP 异常处理及内部错误类
PHP5引入了异常。
异常 是实例化自 内置的Exception类(或其他继承类)的特殊对象。Exception类型的对象可以存放和报告错误信息。
Exception类的构造方法接受两个可选参数 —— 一个消息字符串和一个错误码。该类提供了一些有用的方法来帮助我们分析错误情况。
异常类中的公开方法 | |
方法 | 说明 |
getMessage() | 得到传递给构造方法的消息字符串 |
getCode() | 得到传递给构造方法的错误代码(整数) |
getFile() | 得到发生异常的文件 |
getLine() | 得到发生异常的行号 |
getPrevious() | 得到一个嵌套异常对象 |
getTrace() |
得到一个多维数组,其中保存了引发异常的方法调用的跟踪信息,包括方法、类、 文件和参数数据 |
getTraceAsString() | 得到getTrace()方法返回的数据的字符串版本 |
__toString() |
当Exception对象被用作字符串时,该方法会被自动调用。它会返回一个描述异常 细节的字符串 |
1.
抛出异常
可以使用throw和Exception对象一起来抛出异常,这会导致当前方法的执行被终止,并将错误处理的责任转回给调用方代码。
那么如何让客户端代码知道异常抛出时应该如何处理呢?当我们调用一个可能抛出异常的方法时,可以将方法放在try字句中。每一个try子句之后至少跟着一个catch子句才能处理错误
1 <?php 2 try { 3 echo 'abc'; 4 throw new Exception('抛出异常信息'); 5 echo 'def'; 6 } catch (\Exception $e) { 7 echo $e->getMessage(); 8 } 9 // 输出:abc抛出异常信息
可以看到,catch子句类似于方法声明。当异常抛出后,调用作用域内的catch子句会被调用。Exception对象会作为参数变量自动传递给catch子句。
当有异常抛出时,会终止执行抛出异常的方法,try语句会直接将程序执行的控制权转交给catch语句。
2.
子类化异常
可以通过继承Exception类来创建用户自定义的异常。之所以要这么做,理由有二:一是扩展异常类的功能,二是子类定义新的异常类型能帮我们处理错误。
实际上,可以在try语句中编写多个catch语句。究竟调用哪个catch语句,取决于被抛出的异常的类型,以及参数列表中的类类型提示。下面定义了一些简单的Exception类的子类。
1 <?php 2 class AException extends \Exception 3 { 4 } 5 class BException extends \Exception 6 { 7 } 8 try { 9 throw new BException('抛出AException类错误信息'); 10 } catch (\AException $e) { 11 // AException类异常 12 echo 'A --- ' . $e->getMessage(); 13 } catch (\BException $e) { 14 // BException类异常 15 echo 'B --- ' . $e->getMessage(); 16 } catch (\Exception $e) { 17 // 备用捕捉器 18 echo $e->getMessage(); 19 } 20 // 输出:B --- 抛出AException类错误信息
如以上代码所示,究竟调用哪一个catch子句,却决于被抛出的异常类型。
由于第一个匹配到的catch子句会被执行,请将最通用的类型的catch子句放在最后面,将最特化类型的子句放在最前面。
如果将用于捕捉Exception的catch子句放在了捕捉AExceptioin和BException的子句前面,那么这两个子句将永远不会被调用。因为这两个类型都属于Exception类型,它们会匹配第一个catch子句。
在异常处理中加上一个“备用”的catch子句是一个好习惯,能防止我们在开发过程中向代码加入新的异常却又忘记处理。
注意:如果编写了备用的“catch”语句,那么应当确保已经对那些会在大多数实例中发生的异常进行了处理,否则将导致难以跟踪调试的BUG。
3.
在try/catch语句后使用finally完成清理工作
PHP5.5引入了一个新的子句finally。无论try是否抛出了异常,finally子句都会被执行
1 <?php 2 try { 3 throw new Exception('抛出错误信息'); 4 } catch (\Exception $e) { 5 // 备用捕捉器 6 echo $e->getMessage(); 7 } finally { 8 echo ' 执行finally子句'; 9 } 10 // 输出:抛出错误信息 执行finally子句
注意:如果在try或catch代码块中调用了die()或exit(),那么程序就会终止。finally子句也就不会执行了
4.内部错误类
try和catch子句主要针对的是PHP代码,内部生成的错误会维护它们自己的逻辑。
PHP7引入了Error类,可以让我们自己来管理核心错误。Error类和Exception类实现了同一个内置接口Throwable。因此,Error类也可以调用Exception类的方法
1 try { 2 eval('abc'); 3 } catch (\Exception $e) { 4 echo '程序不会走这'; 5 } catch (\Error $e) { 6 echo get_class($e) . " / " . $e->getMessage(); 7 } 8 // 结果:ParseError / syntax error, unexpected end of file
Error类是针对独立的错误类型进行子类化的,比如上面代码,错误类型为ParseError。可以在catch子句中通过指定Error这个父类或是它的子类来捕捉相匹配的内部错误。
内置的Error子类如下:
错误 | 说明 |
ArithmeticError | 在发生与数学计算(特别是位运算)相关的错误时被抛出 |
AssertionError | 当assert()语言结构(调试中)断言失败时被抛出 |
DivisionByZeroError | 进行除零计算时被抛出 |
ParseError | 在运行时解析PHP(如使用eval())出错时被抛出 |
TypeError | 当错误类型的参数被传递给方法,方法返回一个错误类型的参数,或是传递给方法的参数的数量不正确时被抛出 |