在本教程中,您将学习如何在PHP中引发和捕获异常。
什么是异常
异常是表示发生某种异常事件或错误的信号。可能由于多种原因导致异常,例如,数据库连接或查询失败,您尝试访问的文件不存在等等。
PHP提供了强大的异常处理机制,使您能够以优美的方式处理异常。与PHP的传统错误处理系统相反,异常处理是一种用于处理错误面向对象的方法,它提供了更具指定性和灵活性的错误报告形式。异常模型最早是在PHP 5中引入的。
使用Throw 和 Try ... Catch语句
在基于异常的方法中,程序代码编写在try块中,当在try块中执行代码期间发生异常事件时,可以使用throw语句引发异常。 然后由一个或多个捕获块捕获并解析它。
下面的示例演示异常处理如何工作:
<?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>所有的均成功执行。</p>';
} catch(Exception $e){
//处理异常
echo "<p>捕获的异常: " . $e->getMessage() . "</p>";
}
// 继续执行
echo "<p>Hello World!</p>";
?>
您可能想知道这段代码是关于什么的。好吧,让我们逐一遍历此代码的每个部分,以更好地理解。
代码的用法解释
在PHP的异常处理系统有四种基本部分:try,throw,catch,和Exception类。以下列表描述了各个部分的工作原理。
-
上例中的division()函数检查除数是否等于零。如果是,则通过PHP的throw语句抛出异常。否则,此函数使用给定的数字执行除法并显示结果。
-
然后,在try块中使用不同的参数调用division()函数。如果在try块中执行代码时生成异常,PHP将在该点停止执行并尝试查找相应的catch块。如果找到,则执行catch块中的代码,否则生成致命错误。
-
catch块通常捕获try块中抛出的异常,并创建一个包含异常信息的对象($e)。可以使用异常的getMessage()方法检索来自此对象的错误消息。
在PHP的异常类也提供了getCode(),getFile(),getLine()和getTraceAsString()可用于生成详细的调试信息的方法。
<?php
//关闭默认错误报告
error_reporting(0);
try{
$file = "somefile.txt";
//尝试打开文件
$handle = fopen($file, "r");
if(!$handle){
throw new Exception("无法打开文件!", 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的getCode()方法检索提供的异常代码。
提示:异常仅应用于表示特殊情况;它们不应用于指定正常的应用程序流程,例如,在特定位置跳转到脚本中的其他位置。这样做会不利地影响应用程序的性能。
定义自定义异常
您甚至可以定义自己的自定义异常处理程序,以不同的方式处理不同类型的异常。 它允许您为每种异常类型使用单独的catch块。
您可以通过扩展Exception类来定义自定义异常,因为Exception是所有异常的基类。 自定义异常类继承了PHP Exception类的所有属性和方法。 您还可以将自定义方法添加到自定义异常类。 让我们看一下以下示例:
<?php
//扩展Exception类
class EmptyEmailException extends Exception {}
class InvalidEmailException extends Exception {}
$email = "someuser@example..com";
try{
//如果电子邮件为空,则抛出异常
if($email == ""){
throw new EmptyEmailException("<p>请输入您的电子邮件地址!</p>");
}
//如果电子邮件无效,则抛出异常
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE) {
throw new InvalidEmailException("<p><b>$email</b> 不是有效的电子邮件地址!</p>");
}
// 如果电子邮件有效,则显示成功消息
echo "<p>成功:电子邮件验证成功.</p>";
} catch(EmptyEmailException $e){
echo $e->getMessage();
} catch(InvalidEmailException $e){
echo $e->getMessage();
}
?>
在上面的示例中,我们从Exception基类派生了两个新的异常类:EmptyEmailException和InvalidEmailException。 多个捕获块用于显示不同的错误消息,具体取决于生成的异常类型。
由于这些自定义异常类继承了Exception类的属性和方法,所以我们可以使用异常的类方法,如getMessage(),getLine(),getFile(),等来检索异常对象的错误信息。
设置全局异常处理程序
如本章前面所讨论的,如果未捕获到异常,则PHP会生成一条致命错误,并带有“ Uncaught Exception ...”消息。 此错误消息可能包含敏感信息,例如出现问题的文件名和行号。 如果您不想向用户公开此类信息,则可以创建一个自定义函数,并向set_exception_handler()函数注册该函数以处理所有未捕获的异常。
<?php
function handleUncaughtException($e){
//向用户显示一般错误消息
echo "哎呀!出了点问题。请重试,如果问题仍然存在,请与我们联系。";
// 构造错误字符串
$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块。