Home  >  Article  >  php教程  >  PHP异常处理详解

PHP异常处理详解

WBOY
WBOYOriginal
2016-06-13 10:48:431322browse

异常处理(又称为错误处理)功能提供了处理程序运行时出现的错误或异常情况的方法。

  异常处理通常是防止未知错误产生所采取的处理措施。异常处理的好处是你不用再绞尽脑汁去考虑各种错误,这为处理某一类错误提供了一个很有效的方法,使编程效率大大提高。当异常被触发时,通常会发生:
          当前代码状态被保存
         代码执行被切换到预定义的异常处理器函数
          根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行脚本

          PHP 5 提供了一种新的面向对象的错误处理方法。可以使用检测(try)、抛出(throw)和捕获(catch)异常。即使用try检测有没有抛出(throw)异常,若有异常抛出(throw),使用catch捕获异常。

         一个 try 至少要有一个与之对应的 catch。定义多个 catch 可以捕获不同的对象。PHP 会按这些 catch 被定义的顺序执行,直到完成最后一个为止。而在这些 catch 内,又可以抛出新的异常。

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

     抛出异常,但不去捕获它:


ini_set('display_errors', 'On'); 
error_reporting(E_ALL & ~ E_WARNING); 
$error = 'Always throw this error'; 
throw new Exception($error); 
// 继续执行 
echo 'Hello World'; 
?>  
上面的代码会获得类似这样的一个致命错误:

Fatal error: Uncaught exception 'Exception' with message 'Always throw this error' in E:\sngrep\index.php on line 5 
Exception: Always throw this error in E:\sngrep\index.php on line 5 
Call Stack: 
    0.0005     330680   1. {main}() E:\sngrep\index.php:0 
2. Try, throw 和 catch

要避免上面这个致命错误,可以使用try catch捕获掉。
处理处理程序应当包括:
         Try - 使用异常的函数应该位于 "try" 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。
       Throw - 这里规定如何触发异常。每一个 "throw" 必须对应至少一个 "catch"
       Catch - "catch" 代码块会捕获异常,并创建一个包含异常信息的对象
       抛出异常并捕获掉,可以继续执行后面的代码:

try { 
    $error = 'Always throw this error'; 
    throw new Exception($error); 
 
    // 从这里开始,tra 代码块内的代码将不会被执行 
    echo 'Never executed'; 
 
} catch (Exception $e) { 
    echo 'Caught exception: ',  $e->getMessage(),'
'; 

 
// 继续执行 
echo 'Hello World'; 
?>  

    在 "try" 代码块检测有有没有抛出“throw”异常,这里抛出了异常。
    "catch" 代码块接收到该异常,并创建一个包含异常信息的对象 ($e)。
    通过从这个 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息
    为了遵循“每个 throw 必须对应一个 catch”的原则,可以设置一个顶层的异常处理器来处理漏掉的错误。


3. 扩展 PHP 内置的异常处理类
    用户可以用自定义的异常处理类来扩展 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() 数组 www.2cto.com  
    final function getTraceAsString();          // 已格成化成字符串的 getTrace() 信息 
 
    /* 可重载的方法 */ 
    function __toString();                       // 可输出的字符串 

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

     构建自定义异常处理类:

 
/**
 * 
 * 自定义一个异常处理类
 */ 
 
class MyException extends Exception 

    // 重定义构造器使 message 变为必须被指定的属性 
    public function __construct($message, $code = 0) { 
        // 自定义的代码 
 
        // 确保所有变量都被正确赋值 
        parent::__construct($message, $code); 
    } 
 
    // 自定义字符串输出的样式 */ 
    public function __toString() { 
        return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; 
    } 
 
    public function customFunction() { 
        echo "A Custom function for this type of exception\n"; 
    } 

// 例子 1:抛出自定义异常,但没有默认的异常 
echo ' 例子 1', '
'; 
try { 
    // 抛出自定义异常 
    throw new MyException('1 is an invalid parameter', 5); 
} catch (MyException $e) {      // 捕获异常 
    echo "Caught my exception\n", $e; 
    $e->customFunction(); 
} catch (Exception $e) {        // 被忽略 
    echo "Caught Default Exception\n", $e; 

// 执行后续代码 
// 例子 2: 抛出默认的异常  但没有自定义异常 
echo '
', ' 例子 2:', '
'; 
try { 
     // 抛出默认的异常   
    throw new Exception('2 isnt allowed as a parameter', 6); 
} catch (MyException $e) {      // 不能匹配异常的种类,被忽略 
    echo "Caught my exception\n", $e; 
    $e->customFunction(); 
} catch (Exception $e) {// 捕获异常 
    echo "Caught Default Exception\n", $e; 

// 执行后续代码 
// 例子 3: 抛出自定义异常 ,使用默认异常类对象来捕获 
echo '
', ' 例子 3:', '
'; 
try { 
     // 抛出自定义异常  
    throw new MyException('3 isnt allowed as a parameter', 6); 
} catch (Exception $e) {        // 捕获异常 
    echo "Default Exception caught\n", $e; 

 
// 执行后续代码 
// 例子 4 
echo '
', ' 例子 4:', '
'; 
try { 
    echo 'No Exception '; 
} catch (Exception $e) {        // 没有异常,被忽略 
    echo "Default Exception caught\n", $e; 

 
// 执行后续代码 
           MyException 类是作为旧的 exception 类的一个扩展来创建的。这样它就继承了旧类的所有属性和方法,我们可以使用 exception 类的方法,比如 getLine() 、 getFile() 以及 getMessage()。
4. 嵌套异常处理

    如果在内层 "try" 代码块中异常没有被捕获,则它将在外层级上查找 catch 代码块去捕获。

try { 
    try { 
    throw new MyException('foo!'); 
    } catch (MyException $e) { 
        /* 重新抛出 rethrow it */ 
         $e->customFunction(); 
        throw $e; 
       
     } 
} catch (Exception $e) { 
        var_dump($e->getMessage()); 

5. 设置顶层异常处理器 (Top Level Exception Handler)
    set_exception_handler() 函数可设置处理所有未捕获异常的用户定义函数。 


function myException($exception) 

echo "Exception: " , $exception->getMessage(); 

 
set_exception_handler('myException'); 
throw new Exception('Uncaught Exception occurred'); 
     输出结果:

Exception: Uncaught Exception occurred 

6. 异常的规则
需要进行异常处理的代码应该放入 try 代码块内,以便捕获潜在的异常。
每个 try 或 throw 代码块必须至少拥有一个对应的 catch 代码块。
使用多个 catch 代码块可以捕获不同种类的异常。
可以在 try 代码块内的 catch 代码块中再次抛出(re-thrown)异常。
简而言之:如果抛出了异常,就必须捕获它,否则程序终止执行。


摘自 程序人生,guisu专栏

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn