第 11 章 异常处理

PHP 5 添加了类似于其它语言的异常处理模块。在 PHP 代码中所产生的异常可被 throw 语句抛出并被 catch 语句捕获。需要进行异常处理的代码都必须放入 try 代码块内,以便捕获可能存在的异常。每一个 try 至少要有一个与之对应的 catch。使用多个 catch 可以捕获不同的类所产生的异常。当 try 代码块不再抛出异常或者找不到 catch 能匹配所抛出的异常时,PHP 代码就会在跳转到最后一个 catch 的后面继续执行。当然,PHP 允许在 catch 代码块内再次抛出(throw)异常。

当一个异常被抛出时,其后(译者注:指抛出异常时所在的代码块)的代码将不会继续执行,而 PHP 就会尝试查找第一个能与之匹配的 catch。如果一个异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么 PHP 将会产生一个严重的错误,并且输出 Uncaught Exception ... (未捕获异常)的提示信息。

例 11.1. 抛出一个异常

<?php
try {
   
$error = 'Always throw this error';
   throw new
Exception($error);

   
// &#20174;&#36825;&#37324;&#24320;&#22987;&#65292;tra &#20195;&#30721;&#22359;&#20869;&#30340;&#20195;&#30721;&#23558;&#19981;&#20250;&#34987;&#25191;&#34892;
   
echo 'Never executed';

} catch (
Exception $e) {
   echo
'Caught exception: ',  $e->getMessage(), "\n";
}

// &#32487;&#32493;&#25191;&#34892;
echo 'Hello World';
?>

扩展 PHP 内置的异常处理类

用户可以用自定义的异常处理类来扩展 PHP 内置的异常处理类。以下的代码说明了在内置的异常处理类中,哪些属性和方法在子类中是可访问和可继承的。译者注:以下这段代码只为说明内置异常处理类的结构,它并不是一段有实际意义的可用代码。

例 11.2. 内置的异常处理类

<?php
class Exception
{
   protected
$message = 'Unknown exception';   // &#24322;&#24120;&#20449;&#24687;
   
protected $code = 0;                        // &#29992;&#25143;&#33258;&#23450;&#20041;&#24322;&#24120;&#20195;&#30721;
   
protected $file;                            // &#21457;&#29983;&#24322;&#24120;&#30340;&#25991;&#20214;&#21517;
   
protected $line;                            // &#21457;&#29983;&#24322;&#24120;&#30340;&#20195;&#30721;&#34892;&#21495;

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

   final function
getMessage();                // &#36820;&#22238;&#24322;&#24120;&#20449;&#24687;
   
final function getCode();                   // &#36820;&#22238;&#24322;&#24120;&#20195;&#30721;
   
final function getFile();                   // &#36820;&#22238;&#21457;&#29983;&#24322;&#24120;&#30340;&#25991;&#20214;&#21517;
   
final function getLine();                   // &#36820;&#22238;&#21457;&#29983;&#24322;&#24120;&#30340;&#20195;&#30721;&#34892;&#21495;
   
final function getTrace();                  // backtrace() &#25968;&#32452;
   
final function getTraceAsString();          // &#24050;&#26684;&#25104;&#21270;&#25104;&#23383;&#31526;&#20018;&#30340; getTrace() &#20449;&#24687;

   /* &#21487;&#37325;&#36733;&#30340;&#26041;&#27861; */
   
function __toString();                       // &#21487;&#36755;&#20986;&#30340;&#23383;&#31526;&#20018;
}
?>

如果使用自定义的类来扩展内置异常处理类,并且要重新定义构造函数的话,建议同时调用 parent::__construct() 来检查所有的变量是否已被赋值。当对象要输出字符串的时候,可以重载 __toString() 并自定义输出的样式。

例 11.3. 扩展 PHP 内置的异常处理类

<?php
/**
* &#33258;&#23450;&#20041;&#19968;&#20010;&#24322;&#24120;&#22788;&#29702;&#31867;
*/
class MyException extends Exception
{
   
// &#37325;&#23450;&#20041;&#26500;&#36896;&#22120;&#20351; message &#21464;&#20026;&#24517;&#39035;&#34987;&#25351;&#23450;&#30340;&#23646;&#24615;
   
public function __construct($message, $code = 0) {
       
// &#33258;&#23450;&#20041;&#30340;&#20195;&#30721;

       // &#30830;&#20445;&#25152;&#26377;&#21464;&#37327;&#37117;&#34987;&#27491;&#30830;&#36171;&#20540;
       
parent::__construct($message, $code);
   }

   
// &#33258;&#23450;&#20041;&#23383;&#31526;&#20018;&#36755;&#20986;&#30340;&#26679;&#24335;
   
public function __toString() {
       return
__CLASS__ . ": [{$this->code}]: {$this->message}\n";
   }

   public function
customFunction() {
       echo
"A Custom function for this type of exception\n";
   }
}


/**
* &#21019;&#24314;&#19968;&#20010;&#29992;&#20110;&#27979;&#35797;&#24322;&#24120;&#22788;&#29702;&#26426;&#21046;&#30340;&#31867;
*/
class TestException
{
   public
$var;

   const
THROW_NONE    = 0;
   const
THROW_CUSTOM  = 1;
   const
THROW_DEFAULT = 2;

   function
__construct($avalue = self::THROW_NONE) {

       switch (
$avalue) {
           case
self::THROW_CUSTOM:
               
// &#25243;&#20986;&#33258;&#23450;&#20041;&#24322;&#24120;
               
throw new MyException('1 is an invalid parameter', 5);
               break;

           case
self::THROW_DEFAULT:
               
// &#25243;&#20986;&#40664;&#35748;&#30340;&#24322;&#24120;
               
throw new Exception('2 isnt allowed as a parameter', 6);
               break;

           default:
               
// &#27809;&#26377;&#24322;&#24120;&#30340;&#24773;&#20917;&#19979;&#65292;&#21019;&#24314;&#19968;&#20010;&#23545;&#35937;
               
$this->var = $avalue;
               break;
       }
   }
}


// &#20363;&#23376; 1
try {
   
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
MyException $e) {      // &#25429;&#33719;&#24322;&#24120;
   
echo "Caught my exception\n", $e;
   
$e->customFunction();
} catch (
Exception $e) {        // &#34987;&#24573;&#30053;
   
echo "Caught Default Exception\n", $e;
}

// &#25191;&#34892;&#21518;&#32493;&#20195;&#30721;
var_dump($o);
echo
"\n\n";


// &#20363;&#23376; 2
try {
   
$o = new TestException(TestException::THROW_DEFAULT);
} catch (
MyException $e) {      // &#19981;&#33021;&#21305;&#37197;&#24322;&#24120;&#30340;&#31181;&#31867;&#65292;&#34987;&#24573;&#30053;
   
echo "Caught my exception\n", $e;
   
$e->customFunction();
} catch (
Exception $e) {        // &#25429;&#33719;&#24322;&#24120;
   
echo "Caught Default Exception\n", $e;
}

// &#25191;&#34892;&#21518;&#32493;&#20195;&#30721;
var_dump($o);
echo
"\n\n";


// &#20363;&#23376; 3
try {
   
$o = new TestException(TestException::THROW_CUSTOM);
} catch (
Exception $e) {        // &#25429;&#33719;&#24322;&#24120;
   
echo "Default Exception caught\n", $e;
}

// &#25191;&#34892;&#21518;&#32493;&#20195;&#30721;
var_dump($o);
echo
"\n\n";


// &#20363;&#23376; 4
try {
   
$o = new TestException();
} catch (
Exception $e) {        // &#27809;&#26377;&#24322;&#24120;&#65292;&#34987;&#24573;&#30053;
   
echo "Default Exception caught\n", $e;
}

// &#25191;&#34892;&#21518;&#32493;&#20195;&#30721;
var_dump($o);
echo
"\n\n";
?>