16.2 PHP中的异常处理类及其用法
PHP5增加了类似于其他语言的异常处理模块。这使得在PHP程序中排查错误、捕获异常更加简单容易,也使得PHP程序在健壮性方面有很大改善和提高。这一模块在PHP中的具体体现就是,PHP提供了一个名叫Exception的类完成对PHP程序异常的处理,这个类包含了一些处理异常的函数,这些函数可以捕获程序异常和错误。本节将介绍PHP中的该异常处理类及类函数用法。
16.2.1 PHP中的异常处理类
PHP5提供了内置的异常处理类——Exception,首先介绍该类的以下成员函数。
·getMessage():可以返回对错误描述信息。
·getCode():返回错误代码,以数字形式出现。
·getFile():返回发生错误的文件名。
·getLine():返回发生错误的代码行号。
·getTrace():返回backtrace()数组。
·getTraceAsString():返回已格式化成字符串的、由函数getTrace()所产生的信息。
·__toString():产生异常的字符串信息,它可以重载。注意,该函数最前部是两个下划线。
代码16-1是该内置异常处理类的完整代码,从这个类的定义可以看出哪些属性和方法(成员函数)在用户派生的子类中是可以访问和继承的。
代码16-1 PHP5内置异常处理类的完整代码16-1.php
01 <?php 02 class Exception 03 { 04 protected $message = 'Unknown exception'; // 异常信息 05 protected $code = 0; // 用户自定义异常代码 06 protected $file; // 发生异常的文件名 07 protected $line; // 发生异常的代码行号 08 09 function __construct($message = null, $code = 0); 10 11 final function getMessage(); // 返回异常信息 12 final function getCode(); // 返回异常代码 13 final function getFile(); // 返回发生异常的文件名 14 final function getLine(); // 返回发生异常的代码行号 15 final function getTrace(); //backtrace() 数组 16 final function getTraceAsString(); // 已格式化成字符串的getTrace() 信息 17 18 function __toString(); // 可输出的字符串 19 } 20 ?>
【代码解析】如果使用自定义的类来扩展内置异常处理类,并且要重新定义构造函数,建议同时调用parent::__construct()来检查所有的变量是否已被赋值。当对象要输出字符串的时候,可以重载成员函数__toString()并自定义输出的样式。
16.2.2 PHP程序中捕获异常的方法
如下所示为两种抛出异常的格式。
·try…catch…:该处理异常方式的具体格式如下。
try { // 这里是可能出现异常或错误的代码,比如文件操作、数据库操作等 } catch(Exception $e) { // 输出错误信息 }
·throw:关键字throw用来抛出一个异常。
需要进行异常处理的代码都必须放入try代码块内,以便捕获可能存在的异常。每一个try至少要有一个与之对应的catch。使用多个catch可以捕获不同的类所产生的异常。当try代码块不再抛出异常或者找不到catch能匹配所抛出的异常时,PHP代码就会在跳转到最后一个catch的后面继续执行。
在PHP代码中所产生的异常可被throw语句抛出并被catch语句捕获。当然,PHP允许在catch代码块内再次抛出(throw)异常。当一个异常被抛出时,其后的代码将不会继续执行,而PHP就会尝试继续查找第一个能与之匹配的catch。如果一个异常没有被捕获,而且又没用使用set_exception_handler()作相应的处理的话,那么PHP将会产生一个严重的错误,并且输出UncaughtException...(未捕获异常)的提示信息。
代码16-2是try...catch和throw一起用的示例代码,从这个代码可以看出try…catch和throw在程序中是如何工作的。
代码16-2 使用try…catch捕获并处理异常的示例程序16-2.php
01 <?php 02 try 03 { 04 $error = ' 抛出异常信息,并且跳出try 块<br/>'; 05 if(is_dir('./test')) 06 { 07 echo ' 检测到../ch16 是一个目录'; 08 echo '<br/>'; 09 echo ' 可能继续做其他一些操作'; 10 echo '<br/>'; 11 echo '....'; 12 echo '<br/>'; 13 } 14 else 15 { 16 throw new Exception($error,12345); // 抛出异常 17 } 18 echo ' 上面throw 异常的话,这行代码不会执行,转而执行catch 块<br/>'; 19 } 20 catch(Exception $e) // 获取异常 21 { 22 echo ' 捕获异常: ' . $e->getMessage() . "<br/> 错误代码:" . $e->getCode().'<br/>'; // 显示$error 和 23 12345 24 echo '<br/>'; 25 } 26 27 echo ' 继续执行'; ?>
图16-1 使用try…catch捕获程序异常
【代码解析】这段代码在try块中试着判断当前目录下是否存在名叫test的目录,如果不存在这个目录,那么就会执行第16行语句,通过关键字throw抛出异常。这个异常是一个Exception类的对象,通过new运算符生成,并且用错误信息$error和错误代码12345初始化该对象,以便后面catch该异常时(代码第20行),可以获取这些信息。一旦抛出异常,那么try块中剩下的代码就不再执行,程序流程转至相应的catch块执行。代码16-2的执行结果如图16-1所示。
这段代码中自定义了错误信息和错误代码,通过关键字throw抛出一个异常Exception类的对象$e,最终通过该对象调用其成员函数输出错误信息和代码。
16.2.3 获取异常信息
当一个程序遇到一个错误时,可以建立Exception类的对象来处理,类似于如下代码。
$e = new Exception("Could not open file");
此时,Excetpion类的构造函数将通过一错误信息创建一个该类的对象$e。建立这个对象后,通常使用关键字throw将这个异常(或者说错误)抛出。throw将脚本的执行中止,并使相关的Exception对象对客户代码可用。
Exception类的成员函数getMessage()用来产生一个对错误信息的描述。代码16-3演示了该成员函数的用法。
代码16-3 Exception类的成员函数getMessage()的使用16-3.php
01 <?php 02 $file = './test/readme.txt'; // 指定文件地址 03 04 try 05 { 06 if(is_dir($file)) // 判断是不是目录 07 { 08 echo ' 检测到目录'; 09 } 10 else 11 { 12 // 创建异常对象,错误信息将有Exception 类的成员函数getMessage() 返回 13 throw new Exception(' 未找到该目录或文件'); 14 } 15 } 16 catch(Exception $e) 17 { 18 echo ' 捕获异常: ' . $e->getMessage(); 19 echo '<br/>==============================='; 20 echo '<br/>'; 21 } 22 23 echo ' 程序执行完毕'; 24 ?>
图16-2 使用Exception 类的成员函数getMessage()
【代码解析】这段代码将判断文件是否为目录的代码放在try块中,并且当所判断的文件不是目录时,创建异常类Exception的对象,并使用“未找到该目录或文件”这段信息初始化该对象,如代码第13行所示。这段信息被赋值给Exception类的成员变量$message,这个成员变量可以由Exception类的成员函数getMessage()返回,如这段代码第18行,通过Exception类的对象$e调用函数getMessage()将这个异常信息输出。这段程序的执行结果如图16-2所示。
这里只是举一个简单例子说明如何使用Exception类,以及使用该类的成员函数getMessage()获取异常信息。一般是通过该类派生出处理某种操作的异常处理子类,来完成对异常的处理。在派生类中实现throw出异常,然后在使用这个类的程序中try…catch。这样做的好处是,可以在子类中提供更多更完善有效的自定义功能,还可以区分不同类型的异常。
16.2.4 获取错误发生的文件
有了通过Exception类获取错误信息的程序,获取发生错误的文件名就很简单了。只需在程序中使用Exception类的成员函数getFile()即可,如代码16-4所示。
代码16-4 使用Exception类的成员函数获取发生错误的文件名16-4.php
01 <?php 02 $file = './test/readme.txt'; // 指定文件地址 03 04 try 05 { 06 if(is_dir($file)) // 判断是不是目录 07 { 08 echo ' 检测到目录'; 09 } 10 else 11 { 12 // 创建异常对象,错误信息将有Exception 类的成员函数getMessage() 返回 13 throw new Exception(' 未找到该目录或文件'); 14 } 15 } 16 catch(Exception $e) 17 { 18 echo ' 捕获异常: ' . $e->getMessage(); 19 echo '<br/><br/>'; 20 echo ' 错误所在文件:'. $e->getFile(); 21 echo '<br/>==============================='; 22 echo '<br/>'; 23 } 24 25 echo ' 程序执行完毕'; 26 ?>
【代码解析】这段程序仅仅是在代码16-3的基础上添加了对Exception类的成员函数getFile()的调用,如代码第20行所示,执行结果如图16-3所示。
16.2.5 获取错误发生的行
类似获取错误文件名称的办法,在程序中通过调用Exception类的成员函数getLine(),可以获取错误所在的行号,如代码16-5所示。
代码16-5 使用Exception类的成员函数getLine()获取发生错误的所在行16-5.php
01 <?php 02 $file = './test/readme.txt'; // 指定文件地址 03 04 try 05 { 06 if(is_dir($file)) // 判断是否是目录 07 { 08 echo ' 检测到目录'; 09 } 10 else 11 { 12 // 创建异常对象,错误信息将有Exception 类的成员函数getMessage() 返回 13 throw new Exception(' 未找到该目录或文件'); 14 } 15 } 16 catch(Exception $e) 17 { 18 echo ' 捕获异常: ' . $e->getMessage(); 19 echo '<br/><br/>'; 20 echo ' 错误所在文件:'. $e->getFile(); 21 echo '<br/><br/>'; 22 echo ' 错误所在行号:'. $e->getLine(); 23 echo '<br/>==============================='; 24 echo '<br/>'; 25 } 26 27 echo ' 程序执行完毕'; 28 ?>
【代码解析】这段代码在第22行调用Exception类的成员函数getLine()获取异常发生所在的行号,其执行结果如图16-4所示。
图16-3 使用Exception类的成员函数getFile()
图16-4 使用Exception类的成员函数getLine()