异常(Exception)处理用于在指定的错误发生时改变脚本的正常流程,是PHP 5中的一个新的重要特性。异常处理是一种可扩展、易维护的错误处理统一机制,并提供了一种新的面向对象的错误处理方式。在Java、C#及Python等
语言中很早就提供了这种异常处理机制,如果你对哪一种语言中的异常处理熟悉,那对PHP中提供的异常处理机制也不会陌生。
1.异常处理实现
异常处理和编写程序的流程控制相似,所以也可以通过异常处理实现一种另类的条件选择结构。异常就是在程序运行过程中出现的一些意料之外的事件,如果不对此事件进行处理,则程序在执行时遇到异常将崩溃。处理异常需要在PHP脚本中使用以下语句:
<DIV align=center>
try { //所有需要进行异常处理的代码都必须放入这个代码块内 … … //在这里可以使用throw语句抛出一个异常对象 }catch(ex1) { //使用该代码块捕获一个异常,并进行处理 … … //处理发生的异常,也可再次抛出异常 } |
</DIV>
在PHP代码中所产生的异常可以被throw语句抛出并被catch语句捕获。需要进行异常处理的代码都必须放入try代码块内,以便捕获可能存在的异常。每一个try至少要有一个与之对应的catch,也不能出现单独的catch,另外try和cache之间也不能有任何的代码出现。一个异常处理的简单实例如下所示:
<DIV align=center>
<?php try { $error = 'Always throw this error'; throw new Exception($error); //创建一个异常对象,通过throw语句抛出 echo 'Never executed'; //从这里开始,try代码块内的代码将不会再被执行 } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; //输出捕获的异常消息 } echo 'Hello World'; //程序没有崩溃继续向下执行 ?> |
</DIV>
在上面的代码中,如果try代码块中出现某些错误,我们就可以执行一个抛出异常的操作。在某些编程语言中,例如Java,在出现异常时将自动抛出异常。而在PHP中,异常必须手动抛出。throw关键字将触发异常处理机制,它是一个语言结构,而不是一个函数,但必须给它传递一个对象作为值。在最简单的情况下,可以实例化一个内置的Exception类,就像以上代码所示那样。如果在try语句中有异常对象被抛出,该代码块不会再继续向下执行,而直接跳转到catch中执行。并传递给catch代码块一个对象,也可以理解为被catch代码块捕获的对象,其实就是导致异常被throw语句抛出的对象。在catch代码块中可以简单的输出一些异常的原因,也可以是try代码块中任务的另一个版本解决方案,此外,也可以在这个catch代码块中产生新的异常。最重要的是,在异常处理之后,程序不会崩溃,而会继续执行。
2.扩展PHP内置的异常处理类
在try代码块中,需要使用throw语句抛出一个异常对象,才能跳转到catch代码块中执行,并在catch代码块中捕获并使用这个异常类的对象。虽然在PHP中提供的内置异常处理类Exception,已经具有非常不错的特性,但在某些情况下,可能还要扩展这个类来得到更多的功能。所以用户可以用自定义的异常处理类来扩展PHP内置的异常处理类。以下的代码说明了在内置的异常处理类中,哪些属性和方法在子类中是可访问和可继承的:
内置的异常处理类(Exception)
<DIV align=center>
<?php 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(){} //可输出的字符串 } ?> |
</DIV>
上面这段代码只为说明内置异常处理类Exception的结构,它并不是一段有实际意义的可用代码。如果使用自定义的类作为异常处理类,则必须是扩展内置异常处理类Exception的子类,非Exception类的子类是不能作为异常处理类使用的。如果在扩展内置处理类Exception时重新定义构造函数的话,建议同时调用parent::construct()来检查所有的变量是否已被赋值。当对象要输出字符串的时候,可以重载__toString()并自定义输出的样式。可以在自定义的子类中,直接使用内置异常处理Exception类中的所有成员属性,但不能重新改写从该父类中继承过来的成员方法,因为该类的大多数公有方法都是final的。
创建自定义的异常处理程序非常简单,和传统类的声明方式相同,但该类必须是内置异常处理类Exception的一个扩展。当PHP中发生异常时,可调用自定义异常类中的方法进行处理。创建一个自定义的MyException类,继承了内置异常处理类Exception中的所有属性,并向其添加了自定义的方法。代码及应用如下所示:
扩展PHP内置的异常处理类的应用
<DIV align=center>
<?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); //创建一个自定义的异常类对象,通过throw语句抛出 echo 'Never executed'; //从这里开始,try代码块内的代码将不会再被执行 } catch (MyException $e) { //捕获自定义的异常对象 echo '捕获异常: '.$e; //输出捕获的异常消息 $e->customFunction(); //通过自定义的异常对象中的方法处理异常 } echo '你好呀'; //程序没有崩溃继续向下执行 ?> |
</DIV>
在自定义的MyException类中,使用父类中的构造方法检查所有的变量是否已被赋值。而且重载了父类中的__toString()方法,输出自己定制捕获的异常消息。自定义和内置的异常处理类,在使用上没有多大区别,只不过在自定义的异常处理类中,可以调用为具体的异常专门编写的处理方法。
3.捕获多个异常
在try代码块之后,必须至少给出一个catch代码块,也可以将多个catch代码块与一个try代码块进行关联。如果每个catch代码块可以捕获一个不同类型的异常,那么使用多个catch就可以捕获不同的类所产生的异常。当产生一个异常时,PHP将查询一个匹配的catch代码块。如果有多个catch代码块,传递给每一个catch代码块的对象必须具有不同的类型,这样PHP可以找到需要进入哪一个catch代码块。当try代码块不再抛出异常或者找不到catch能匹配所抛出的异常时,PHP代码就会在跳转到最后一个 catch 的后面继续执行。多个异常的捕获的示例如下:
内置的异常处理类(Exception)
<DIV align=center>
<?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 " |