PHP 异常处理
在本教程中,你将学习如何在 PHP 中抛出和捕获异常。
什么是例外
异常是指示某种异常事件或错误发生的信号。由于各种原因可能导致异常,例如,数据库连接或查询失败,你尝试访问的文件不存在,等等。
PHP 提供了一种强大的异常处理机制,允许你以优雅的方式处理异常。与 PHP 的传统错误处理系统相反,异常处理是面向对象的处理错误的方法,它提供了更加可控和灵活的错误报告形式。PHP 5 中首次引入了异常模型。
使用 throw
和 try...catch
语句
在基于异常的方法中,程序代码是在 try
块中编写的,当在 try
块中执行代码期间发生异常事件时,可以使用 throw
语句抛出异常。然后由一个或多个 catch
块捕获并解决它。
以下示例演示了异常处理的工作原理:
<?php
function division($dividend, $divisor){
// Throw exception if divisor is zero
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);
// If exception is thrown following line won't execute
echo '<p>All divisions performed successfully.</p>';
} catch(Exception $e){
// Handle the exception
echo "<p>Caught exception: " . $e->getMessage() . "</p>";
}
// Continue execution
echo "<p>Hello World!</p>";
?>
你可能想知道这段代码到底是什么。好吧,让我们逐个浏览这段代码的每一部分,以便更好地理解。
代码说明
在 PHP 的异常处理系统有四种基本部分: try
, throw
, catch
,和 Exception 类。以下列表描述了每个部件的确切工作方式。
- 上例中的
division()
函数检查除数是否等于零。如果是,则通过 PHPthrow
语句抛出异常。否则,此功能使用给定的数字执行除法并显示结果。 - 稍后,在具有不同参数
division()
的try
块内调用该函数。如果在try
块内执行代码时生成异常,PHP 将在此时停止执行并尝试查找相应的catch
块。如果找到,catch
则执行该块中的代码,否则,将生成致命错误。 - 该
catch
块通常捕获try
块中抛出的异常并创建包含异常信息的对象($e
)。可以使用 Exception 的getMessage()
方法检索此对象的错误消息。
在 PHP 的异常类也提供了 getCode()
, getFile()
, getLine()
和 getTraceAsString()
可用于生成详细的调试信息的方法。
<?php
// Turn off default error reporting
error_reporting(0);
try{
$file = "somefile.txt";
// Attempt to open the file
$handle = fopen($file, "r");
if(!$handle){
throw new Exception("Cannot open the file!", 5);
}
// Attempt to read the file contents
$content = fread($handle, filesize($file));
if(!$content){
throw new Exception("Could not read file!", 10);
}
// Closing the file handle
fclose($handle);
// Display file contents
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()
方法检索。
提示: 例外仅应用于表示特殊情况; 它们不应该用于控制正常的应用程序流,例如,在特定点跳转到脚本中的另一个位置。这样做会对应用程序的性能产生负面影响。
定义自定义异常
你甚至可以定义自己的自定义异常处理程序,以不同的方式处理不同类型的异常。它允许你为每种异常类型使用单独的 catch
块。
你可以通过扩展 Exception 类来定义自定义异常,因为 Exception 是所有异常的基类。自定义异常类从 PHP 的 Exception 类继承所有属性和方法。你还可以将自定义方法添加到自定义异常类。我们来看看下面的例子:
<?php
// Extending the Exception class
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
$email = "someuser@example..com";
try{
// Throw exception if email is empty
if($email == ""){
throw new EmptyEmailException("<p>Please enter your E-mail address!</p>");
}
// Throw exception if email is not valid
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
throw new InvalidEmailException("<p><b>$email</b> is not a valid E-mail address!</p>");
}
// Display success message if email is valid
echo "<p>SUCCESS: Email validation successful.</p>";
} catch(EmptyEmailException $e){
echo $e->getMessage();
} catch(InvalidEmailException $e){
echo $e->getMessage();
}
?>
在上面的例子中,我们已经得出了两个新的异常类:从 Exception 基类来的 EmptyEmailException,和 InvalidEmailException。多个 catch
块用于显示不同的错误消息,具体取决于生成的异常类型。
由于这些自定义异常类继承了 Exception 类的属性和方法,所以我们可以使用异常的类方法,如 getMessage()
, getLine()
, getFile()
,等来检索异常对象的错误信息。
设置全局异常处理程序
正如我们在本章前面讨论的那样,如果没有捕获到异常,PHP 会生成带有 Uncaught Exception ...
消息的致命错误。此错误消息可能包含出现问题的敏感信息,如文件名和行号。如果你不希望向用户公开此类信息,则可以创建自定义函数并将其注册到 set_exception_handler()
函数以处理所有未捕获的异常。
<?php
function handleUncaughtException($e){
// Display generic error message to the user
echo "Opps! Something went wrong. Please try again, or contact us if the problem persists.";
// Construct the error string
$error = "Uncaught Exception: " . $message = date("Y-m-d H:i:s - ");
$error .= $e->getMessage() . " in file " . $e->getFile() . " on line " . $e->getLine() . "\n";
// Log details of error in a file
error_log($error, 3, "var/log/exceptionLog.log");
}
// Register custom exception handler
set_exception_handler("handleUncaughtException");
// Throw an exception
throw new Exception("Testing Exception!");
?>
注意: 未捕获的异常将始终导致脚本终止。因此,如果你希望脚本继续执行超出发生异常的点,则每个 try
块必须至少有一个相应的 catch
块。