PHP 错误处理

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

处理错误

有时你的应用程序将无法按预期运行,从而导致错误。有许多原因可能导致错误,例如:

  • Web 服务器可能会用尽磁盘空间
  • 用户可能在表单字段中输入了无效值
  • 你尝试访问的文件或数据库记录可能不存在
  • 应用程序可能没有写入磁盘上文件的权限
  • 应用程序需要访问的服务可能暂时不可用

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

专业应用程序必须具有正常处理此类运行时错误的功能。通常这意味着更清楚,更准确地告知用户问题。

了解错误级别

通常,当存在阻止脚本正常运行的问题时,PHP 引擎会触发错误。每个错误由整数值和相关常量表示。下表列出了一些常见错误级别:

错误级别 描述
E_ERROR 1 致命的运行时错误,无法从中恢复。立即停止执行脚本。
E_WARNING 2 运行时警告。它是非致命的,大多数错误往往属于这一类。不停止执行脚本。
E_NOTICE 8 运行时通知。指示脚本遇到可能出错的内容,尽管在正常运行脚本时也可能出现这种情况。
E_USER_ERROR 256 致命的用户生成的错误消息。这类似于 E_ERROR ,除了它是由 PHP 脚本使用函数 trigger_error() 而不是 PHP 引擎生成的。
E_USER_WARNING 512 非致命的用户生成的警告消息。这就像是一个 E_WARNING ,除了它是由 PHP 脚本使用函数 trigger_error() 而不是 PHP 生成的。发动机
E_USER_NOTICE 1024 用户生成的通知消息。这类似于 E_NOTICE ,除了它是由 PHP 脚本使用函数 trigger_error() 而不是 PHP 引擎生成的。
E_STRICT 2048 并非严格意义上的错误,但只要 PHP 遇到可能导致问题或转发不兼容的代码就会触发
E_ALL 8191 E_STRICT PHP 5.4.0 之外的所有错误和警告。

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

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

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

请考虑以下示例,它只是尝试打开文本文件以进行只读。

<?php
// Try to open a non-existent file
$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.php on 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. 

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

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

创建自定义错误处理程序

你可以创建自己的错误处理函数来处理 PHP 引擎生成的运行时错误。自定义错误处理程序为你提供更大的灵活性和更好的错误控制,它可以检查错误并决定如何处理错误,它可能向用户显示消息,在文件或数据库中记录错误或发送邮件,尝试解决问题并继续,退出脚本的执行或完全忽略错误。

自定义错误处理程序函数必须能够处理至少两个参数(errno 和 errstr),但是它可以选择接受另外三个参数(errfile,errline 和 errcontext),如下所述:

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

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

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
?>

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

<?php
// Error handler function
function customError($errno, $errstr){
    echo "<b>Error:</b> [$errno] $errstr";
}
 
// Set error handler
set_error_handler("customError");
 
// Trigger error
echo($test);
?>

错误记录

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

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

<?php
function calcDivision($dividend, $divisor){
    if($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", 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("There was a problem, please try again.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>

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

你还可以使用相同的 error_log() 功能发送包含错误详细信息的电子邮件。

<?php
function calcDivision($dividend, $divisor){
    if ($divisor == 0){
        trigger_error("calcDivision(): The divisor cannot be zero", 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("There was a problem, please try again. Error report submitted to webmaster.");
}
set_error_handler("customError");
echo calcDivision(10, 0);
echo "This will never be printed.";
?>

触发错误

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

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

trigger_error ("There was a problem."); 

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

<?php
function calcDivision($dividend, $divisor){
    return($dividend / $divisor);
}
 
// Calling the function
echo calcDivision(10, 0);
?>

如果将值 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);
    }
}
 
// Calling the function
echo calcDivision(10, 0);
?>

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

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

如你所见,第二个示例生成的错误消息与前一个示例相比更清楚地解释了问题。