PHP 错误处理

在本教程中,您将学习如何使用PHP的错误处理功能来优雅地处理错误情况。

处理错误

有时,您的应用程序将无法正常运行,从而导致错误。有多种可能导致错误的原因,例如:

  • Web服务器可能磁盘空间不足

  • 用户可能在表单字段中输入了无效的值

  • 您尝试访问的文件或数据库记录可能不存在

  • 应用程序可能没有写磁盘上文件的权限

  • 应用程序需要访问的服务可能暂时不可用

这些类型的错误称为运行时错误,因为它们在脚本运行时发生。它们不同于在脚本运行之前需要修复的语法错误。

专业的应用程序必须具有适当处理此类运行时错误的功能。通常,这意味着更清楚,准确地将问题告知用户究竟发生了什么。

了解错误级别

通常,当出现导致脚本无法正常运行的问题时,PHP引擎会触发错误。每个错误都由一个整数值和一个关联的常数表示。下表列出了一些常见的错误级别:

错误等级描述
E_ERROR1

致命的运行时错误,无法恢复。 脚本的执行将立即停止。

E_WARNING2

运行时警告。它不是致命的,大多数错误都属于这一类。脚本的执行不会停止。

E_NOTICE8

运行时通知。指示脚本遇到了可能发生错误的情况,尽管在正常运行脚本时也可能发生这种情况。

E_USER_ERROR256

用户生成的致命错误消息。这类似于E_ERROR,只是它是由PHP脚本使用函数trigger_error()而不是PHP引擎生成的。

E_USER_WARNING512非致命的用户生成的警告消息。 这类似于E_WARNING,但它是由PHP脚本使用函数trigger_error()而不是PHP引擎生成的。
E_USER_NOTICE1024

用户生成的通知消息。 这类似于E_NOTICE,但它是由PHP脚本使用函数trigger_error()而非PHP引擎生成的。

E_STRICT2048

严格来说不是错误,但只要PHP遇到可能导致问题或向前不兼容的代码就会触发

E_ALL8191

所有错误和警告,PHP 5.4.0之前的E_STRICT除外。

有关更多错误级别,请查阅有关的参考。

每当PHP脚本遇到问题时,PHP引擎都会触发错误,但是您也可以自己触发错误,以生成更多用户友好的错误消息。这样,您可以使应用程序更加复杂。以下部分描述了一些用于处理PHP错误的常用方法:

使用die()函数的基本错误处理

考虑以下示例,该示例仅尝试以只读方式打开文本文件。

<?php
//尝试打开不存在的文件
$file = fopen("sample.txt", "r");
?>

如果文件不存在,您可能会收到如下错误:

Warning: fopen(sample.txt) [function.fopen]: failed to open stream: No such file or directory in C:\wamp\www\project\test.phpon line 2

如果我们遵循一些简单的步骤,则可以防止用户收到此类错误消息。

<?php
if(file_exists("sample.txt")){
    $file = fopen("sample.txt", "r");
} else{
    die("Error: The file you are trying to access doesn't exist.");
}
?>

现在,如果您运行上述脚本,您将得到如下错误消息:

Error: The file you are trying to access doesn't exist.

正如您可以看到的,通过在尝试访问文件之前实现简单的检查文件是否存在,我们可以生成对用户更有意义的错误消息。

如果未找到“ sample.txt”文件,则上面使用的die()函数仅显示自定义错误消息并终止当前脚本。

创建一个自定义错误处理程序

您可以创建自己的错误处理函数来处理PHP引擎生成的运行时错误。 自定义错误处理程序为您提供了更大的灵活性和对错误的更好控制,它可以检查错误并决定如何处理错误,它可能会向用户显示一条消息、将错误记录在文件或数据库中或通过电子邮件发送、尝试修复问题并继续、退出脚本执行或完全忽略错误。
自定义错误处理函数必须能够处理至少两个参数(errno和errstr),但是它可以选择接受另外三个参数(errfile、errline和errcontext),如下所述:

参数描述
必需 - 以下参数是必需的
errno以整数形式指定错误级别。这对应于适当的错误级别常量(E_ERROR,E_WARNING等)
errstr将错误消息指定为字符串
可选 - 以下参数是可选的
errfile以字符串形式指定发生错误的脚本文件的文件名
errline以字符串形式指定发生错误的行号
errcontext指定一个数组,其中包含发生错误时存在的所有变量及其值。对调试有用

下面是一个简单的自定义错误处理函数示例。 无论多么微不足道,只要发生错误,就会触发这个处理程序customError()。 然后,它将错误的详细信息输出到浏览器并停止执行脚本。

<?php
//错误处理函数
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
?>

您需要告诉PHP使用您的自定义错误处理函数-只需调用内置set_error_handler()函数,并传入函数名称即可。

<?php
//错误处理函数
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
 
//设置错误处理程序
set_error_handler("customError");
 
//触发错误
echo($test);
?>

错误记录

在文本文件中记录错误消息

您还可以将错误的详细信息记录到日志文件中,如下所示:

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("calcDivision(): 除数不能为零", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";
    
    error_log($message, 3, "logs/app_errors.log");
    die("出现问题,请重试。");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "这个永远不会被打印。";
?>

通过电子邮件发送错误消息

您也可以使用相同的error_log()函数发送带有错误详细信息的电子邮件。

<?php
function calcDivision($dividend, $divisor){
    if ($divisor == 0){
        trigger_error("calcDivision(): 除数不能为零", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
function customError($errno, $errstr, $errfile, $errline, $errcontext){
    $message = date("Y-m-d H:i:s - ");
    $message .= "Error: [" . $errno ."], " . "$errstr in $errfile on line $errline, ";
    $message .= "Variables:" . print_r($errcontext, true) . "\r\n";
    
    error_log($message, 1, "webmaster@example.com");
    die("出现问题,请重试。 错误报告已提交给网站管理员。");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "这永远不会被打印出来。";
?>

触发错误

尽管PHP引擎在遇到脚本问题时会触发错误,但是您也可以自己触发错误。这可以帮助使您的应用程序更强大,因为它可以在潜在问题变成严重错误之前对其进行标记。

要从脚本内触发错误,请调用trigger_error()函数,并传入要生成的错误消息:

trigger_error("出现问题了。");

考虑以下计算两个数字除法的函数。

<?php
function calcDivision($dividend, $divisor){
    return($dividend / $divisor);
}
 
//调用函数
echo calcDivision(10, 0);
?>

如果将零值作为$divisor参数传递,则PHP引擎生成的错误将类似于以下内容:

Warning: Division by zero in C:\wamp\www\project\test.php on line 3

此消息看起来内容不多。看以下使用trigger_error()函数生成错误的示例。

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("The divisor cannot be zero", E_USER_WARNING);
        return false;
    } else{
        return($dividend / $divisor);
    }
}
 
//调用函数
echo calcDivision(10, 0);
?>

现在,脚本生成此错误消息:

Warning: The divisor cannot be zero in C:\wamp\www\project\error.php on line 4  	

正如您看到的,第二个示例生成的错误消息与上一个示例相比更加清楚地说明了问题。