PHP 基础教程
PHP 高级教程
PHP & MySQL DATABASE
PHP 示例
PHP 参考手册

PHP 异常处理

在本教程中,您将学习如何在 PHP 中抛出和捕获异常。

什么是异常

异常是表示发生了某种异常事件或错误的信号。 异常可能由多种原因引起,例如数据库连接或查询失败、您尝试访问的文件不存在等等。

PHP 提供了强大的异常处理机制,允许您以优雅的方式处理异常。 与 PHP 传统的错误处理系统相反,异常处理是处理错误的面向对象方法,它提供了更加可控和灵活的错误报告形式。 异常模型最初是在 PHP 5 中引入的。

使用 Throw 和 Try...Catch 语句

在基于异常的方法中,程序代码写在try块中,当try块中的代码执行过程中发生异常事件时,可以使用throw语句抛出异常。 然后它被一个或多个 catch 块捕获和解析。

以下示例演示了异常处理的工作原理:

示例

Download
<?php
function division($dividend, $divisor){
    // 如果除数为零则抛出异常
    if($divisor == 0){
        throw new Exception('Division by zero.');
    } else{
        $quotient = $dividend / $divisor;
        echo "<p>$dividend / $divisor = $quotient</p>";
    }
}
 
try{
    division(10, 2);
    division(30, -4);
    division(15, 0);
    
    // 如果抛出异常以下行将不会执行
    echo '<p>All divisions performed successfully.</p>';
} catch(Exception $e){
    // 处理异常
    echo "<p>Caught exception: " . $e->getMessage() . "</p>";
}
 
// 继续执行
echo "<p>Hello World!</p>";
?>

您可能想知道这段代码是关于什么的。 好吧,让我们一一浏览这段代码的每一部分,以便更好地理解。

代码说明

PHP 的异常处理系统基本上有四个部分:try, throw, catch、Exception 类。 以下列表描述了每个部分的确切工作原理。

  • 上例中的 division() 函数检查除数是否等于 0。 如果是,则通过 PHP 的 throw 语句引发异常。 否则,此函数使用给定的数字执行除法并显示结果。
  • 稍后,在具有不同参数的 try 块中调用 division() 函数。 如果在执行 try 块中的代码时产生异常,PHP 会在该点停止执行并尝试查找相应的 catch 块。 如果找到,则执行该 catch 块中的代码,如果没有,则生成致命错误。
  • catch 块通常捕获在 try 块中抛出的异常,并创建一个包含异常信息的对象 ($e)。 可以使用 Exception 的 getMessage() 方法检索来自该对象的错误消息。

PHP 的 Exception 类还提供了 getCode()getFile()getLine()getTraceAsString() 方法,可用于生成详细的调试信息。

示例

Download
<?php
// 关闭默认错误报告
error_reporting(0);
 
try{
    $file = "somefile.txt";
    
    // 尝试打开文件
    $handle = fopen($file, "r");
    if(!$handle){
        throw new Exception("Cannot open the file!", 5);
    }
    
    //尝试读取文件内容
    $content = fread($handle, filesize($file));
    if(!$content){
        throw new Exception("Could not read file!", 10);
    }
    
    // 关闭文件句柄
    fclose($handle);
    
    // 显示文件内容
    echo $content;
} catch(Exception $e){
    echo "<h3>Caught Exception!</h3>";
    echo "<p>Error message: " . $e->getMessage() . "</p>";    
    echo "<p>File: " . $e->getFile() . "</p>";
    echo "<p>Line: " . $e->getLine() . "</p>";
    echo "<p>Error code: " . $e->getCode() . "</p>";
    echo "<p>Trace: " . $e->getTraceAsString() . "</p>";
}
?>

Exception 的构造函数可选地接受异常消息和异常代码。 虽然异常消息通常用于显示有关问题的一般信息,但异常代码可用于对错误进行分类。 提供的异常代码可以稍后通过 Exception 的 getCode() 方法检索。

提示: Exception 只能用于表示异常情况; 它们不应用于控制正常的应用程序流程,例如,在特定点跳转到脚本中的另一个位置。 这样做会对您的应用程序的性能产生不利影响。


定义自定义异常

您甚至可以定义自己的自定义异常处理程序,以不同的方式处理不同类型的异常。 它允许您为每种异常类型使用单独的 catch 块。

您可以通过扩展 Exception 类来定义自定义异常,因为 Exception 是所有异常的基类。 自定义异常类继承了 PHP 的 Exception 类的所有属性和方法。 您还可以将自定义方法添加到自定义异常类。 让我们看看下面的例子:

示例

Download
<?php
// 扩展异常类
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
 
$email = "someuser@example..com";
 
try{
    // 如果电子邮件为空,则抛出异常
    if($email == ""){
        throw new EmptyEmailException("<p>Please enter your E-mail address!</p>");
    }
    
    // 如果电子邮件无效,则抛出异常
    if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {           
        throw new InvalidEmailException("<p><b>$email</b> is not a valid E-mail address!</p>");
    }
    
    // 如果电子邮件有效,则显示成功消息
    echo "<p>SUCCESS: Email validation successful.</p>";
} catch(EmptyEmailException $e){
    echo $e->getMessage();
} catch(InvalidEmailException $e){
    echo $e->getMessage();
}
?>

在上面的示例中,我们派生了两个新的异常类:EmptyEmailExceptionInvalidEmailException 来自 Exception 基类。 多个 catch 块用于显示不同的错误消息,具体取决于生成的异常类型。

由于这些自定义异常类继承了异常类的属性和方法,所以我们可以使用异常的类方法如 getMessage(), getLine(), getFile() 等从异常对象中获取错误信息。


设置全局异常处理程序

正如我们在本章前面所讨论的,如果一个异常没有被捕获,PHP 会生成一个带有"Uncaught Exception ..."消息的致命错误。 此错误消息可能包含敏感信息,例如出现问题的文件名和行号。 如果您不想将此类信息暴露给用户,您可以创建一个自定义函数并将其注册到 set_exception_handler() 函数以处理所有未捕获的异常。

示例

Download
<?php
function handleUncaughtException($e){
    // 向用户显示一般错误消息
    echo "Opps! Something went wrong. Please try again, or contact us if the problem persists.";
    
    // 构造错误字符串
    $error = "Uncaught Exception: " . $message = date("Y-m-d H:i:s - ");
    $error .= $e->getMessage() . " in file " . $e->getFile() . " on line " . $e->getLine() . "\n";
    
    // 在文件中记录错误的详细信息
    error_log($error, 3, "var/log/exceptionLog.log");
}
 
// 注册自定义异常处理程序
set_exception_handler("handleUncaughtException");
 
// 抛出异常
throw new Exception("Testing Exception!");
?>

注意:未捕获的异常总是会导致脚本终止。 因此,如果您希望脚本在异常发生点之后继续执行,则每个 try 块必须至少有一个对应的 catch 块。

Advertisements