PHP 错误处理
PHP 错误与异常处理
Section titled “PHP 错误与异常处理”有效的错误处理对于构建健壮且安全的 PHP 应用程序至关重要。它包括检测错误、适当地报告它们(为开发者记录日志,为用户显示友好消息)以及在可能的情况下从中恢复。
PHP 中的错误类型
Section titled “PHP 中的错误类型”PHP 区分几种不同类型的问题:
- 通知(Notices): 脚本执行期间发现的非关键问题(例如,使用了未定义的变量)。脚本通常会继续执行。
- 警告(Warnings): 更严重的非致命错误(例如,包含了不存在的文件)。脚本通常会继续执行。
- 致命错误(Fatal Errors): 中止脚本执行的严重错误(例如,调用了未定义的函数、解析错误)。在 PHP 7+ 中,许多此类错误现在会抛出
Error异常。 - 异常(Exceptions): 一种面向对象的方式,用于处理运行时错误或异常情况(实现了
Throwable接口的Exception和Error类)。将在异常章节中介绍。
现代 PHP 严重依赖于异常模型(try...catch...finally)来处理运行时问题,包括许多以前属于致命错误的错误。
基本错误处理:die() 或 exit() 结构
Section titled “基本错误处理:die() 或 exit() 结构”处理致命情况的一种非常简单但通常比较粗糙的方法是使用 die() 或 exit()(它们是别名)来停止脚本执行。
示例:在打开文件前检查文件是否存在:
<?php$filename = "nonexistent_file.txt";
if (!file_exists($filename)) { // Stop script execution and output a message die("Error: File '{$filename}' not found. Cannot proceed.");}
// This code will only run if the file existsecho "File exists, proceeding...";$fileHandle = fopen($filename, "r");// ... process file ...?>尽管 die() 可以阻止在发生严重错误后进一步执行,但它提供的用户体验很差,并且绕过了任何清理逻辑(例如关闭数据库连接)。在生产应用程序中,通常不建议使用它,而应优先考虑异常或更优雅的错误处理方式。
配置错误报告
Section titled “配置错误报告”PHP 的错误报告行为由 php.ini 配置文件中的设置控制,或者在脚本中通过 error_reporting() 和 ini_set() 等函数动态控制。
关键指令(php.ini):
error_reporting(例如E_ALL):设置 PHP 应该报告的错误级别。开发期间建议使用E_ALL来捕获所有问题(通知、警告等)。display_errors(例如On或Off):确定是否应在浏览器输出中直接显示错误。开发期间应设置为On,但在生产环境中必须设置为Off,以避免暴露敏感信息。log_errors(例如On或Off):确定是否应将错误写入日志文件。生产环境应设置为On。error_log(例如/var/log/php_errors.log或syslog):指定当log_errors设置为On时,错误应记录到哪个文件或系统日志(syslog)。
开发环境与生产环境设置:
- 开发环境:
error_reporting = E_ALL,display_errors = On,log_errors = On(可选,但推荐)。 - 生产环境:
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT(或类似设置,如果需要,报告除通知/废弃警告之外的大多数错误),display_errors = Off,log_errors = On,error_log = /path/to/secure/log/file。
你可以在脚本中临时覆盖 php.ini 设置:
<?php// Recommended for development: Show all errorsini_set('display_errors', '1');ini_set('display_startup_errors', '1');error_reporting(E_ALL);
// Example of triggering a noticeecho $undefinedVariable;
// Code that might cause a warninginclude 'non_existent_file.php';?>自定义错误处理程序 (set_error_handler)
Section titled “自定义错误处理程序 (set_error_handler)”对于非异常的错误(主要是通知和警告),你可以使用 set_error_handler() 定义一个自定义函数来处理它们。这允许你拦截这些错误并决定如何记录或显示它们。
鉴于现在许多致命错误会抛出 Error 异常,这种方法的需求已不如以前普遍,但它对于在开发期间记录通知/警告或将特定警告转换为异常仍然有用。
处理函数接收的参数包括错误级别、消息、文件、行号和上下文。
语法:set_error_handler(callable $callback, int $error_levels = E_ALL | E_STRICT)
示例:记录警告和通知:
<?phpdeclare(strict_types=1);
// Custom error handler functionfunction customErrorHandler(int $errno, string $errstr, string $errfile, int $errline): bool{ // Log the error (adjust path and format as needed) $logMessage = "[" . date("Y-m-d H:i:s") . "] Error [$errno]: $errstr in $errfile on line $errline\n"; error_log($logMessage, 3, "/path/to/your/app_errors.log");
// To prevent PHP's internal handler from running, return true. // If you return false or nothing, PHP's standard error handling will proceed. // Don't display errors directly in production! if (ini_get('display_errors')) { // Only display if configured echo "**Error Caught:** [$errno] $errstr in $errfile:$errline<br>"; }
// Let PHP continue if it's just a notice/warning, but halt for user errors maybe? // This logic depends on your needs. /* switch ($errno) { case E_USER_ERROR: echo "Fatal error caught. Halting."; exit(1); break; case E_USER_WARNING: case E_USER_NOTICE: // Logged above, continue execution break; default: // Standard PHP notice/warning, logged above, continue execution break; } */
return true; // Suppress PHP's default handler for handled types}
// Set the custom handler to catch all errors (including notices, warnings)set_error_handler('customErrorHandler', E_ALL);
// Trigger a noticeecho $someUndefinedVar;
// Trigger a warninginclude 'non_existent_script.php';
echo "Script execution might continue depending on handler logic...";?>注意:由 set_error_handler() 设置的自定义错误处理程序无法处理像解析错误这样的致命错误,或者 PHP 7+ 中现在会抛出 Error 异常的大多数错误。可以使用 register_shutdown_function() 来检测某些致命错误,或使用 try...catch (Throwable $t) 来处理异常/错误。
触发自定义错误 (trigger_error)
Section titled “触发自定义错误 (trigger_error)”你可以使用 trigger_error() 函数在代码中生成用户级别的错误(通知、警告或致命错误)。这对于指示应用程序逻辑或库使用中的问题非常有用。
语法:trigger_error(string $message, int $error_type = E_USER_NOTICE)
错误类型:
E_USER_NOTICE(默认):类似于标准的 PHP 通知。E_USER_WARNING:类似于标准的 PHP 警告。E_USER_ERROR:类似于致命的 PHP 错误(会中止执行,除非被自定义错误处理程序捕获并退出)。E_USER_DEPRECATED:指示已弃用的功能。
示例:
<?phpfunction calculateDivision(float $numerator, float $denominator): float { if ($denominator == 0) { // Trigger a user warning for invalid input trigger_error("Division by zero attempted", E_USER_WARNING); return NAN; // Not a Number } if ($numerator < 0) { // Example: Trigger a notice if numerator is negative trigger_error("Numerator is negative, proceeding anyway.", E_USER_NOTICE); } return $numerator / $denominator;}
// Set a simple error handler to see the triggered errorsset_error_handler(function($errno, $errstr){ echo "Triggered Error: $errstr\n";}, E_USER_NOTICE | E_USER_WARNING);
$result1 = calculateDivision(10, 0);echo "Result 1: $result1\n";
$result2 = calculateDivision(-5, 2);echo "Result 2: $result2\n";?>输出:
Triggered Error: Division by zero attemptedResult 1: NANTriggered Error: Numerator is negative, proceeding anyway.Result 2: -2.5错误日志记录 (error_log)
Section titled “错误日志记录 (error_log)”error_log() 函数允许你显式地将消息发送到 PHP 配置的错误日志机制(文件、syslog),甚至通过电子邮件发送(尽管对于大量日志,通常不建议使用电子邮件日志)。
这对于记录特定的应用程序事件或详细的调试信息非常有用,可以将它们与标准的 PHP 错误分开。
语法:error_log(string $message, int $message_type = 0, ?string $destination = null, ?string $additional_headers = null): bool
常见的 message_type 值:
0(默认):将消息发送到 PHP 的系统日志记录器(使用php.ini中的error_log指令)。1:通过电子邮件将消息发送到destination参数指定的地址。3:将消息附加到destination指定的文件。
示例:将自定义消息记录到标准的 PHP 错误日志:
<?php$userId = 123;$action = "update_profile";
// ... some logic ...
if (/* some condition indicating success */ true) { $logMsg = "User ID {$userId} successfully performed action '{$action}'."; error_log($logMsg); // Sends to the configured PHP error log (type 0) echo "Action logged.";} else { $logMsg = "User ID {$userId} failed action '{$action}'."; error_log($logMsg); // Log failure too echo "Action failure logged.";}?>示例:记录到特定文件(确保权限正确):
<?php$customLogFile = '/var/log/my_app_debug.log'; // Make sure this file is writable by the web server$debugInfo = "Processing started for request ID: " . uniqid();
error_log(date('[Y-m-d H:i:s] ') . $debugInfo . "\n", 3, $customLogFile);echo "Debug info written to custom log.";?>注意:避免记录敏感数据,例如密码或个人信息。