本文目录导读:

register_shutdown_function 是 PHP 中一个非常有用的函数,用于注册一个在脚本执行完成后(无论是正常结束还是发生致命错误)才会被调用的回调函数。
核心作用
捕获致命错误
最常见的用途是捕获 PHP 致命错误,因为 try-catch 无法捕获 E_ERROR 级别的错误。
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== NULL) {
// 发生致命错误时执行清理操作
error_log("Fatal error: " . $error['message']);
}
});
资源清理
确保在脚本结束时释放资源,即使发生了意外错误也能正常执行:
// 数据库连接清理
$db = new mysqli('localhost', 'user', 'pass', 'db');
register_shutdown_function(function() use ($db) {
if ($db->connect_error === null) {
$db->close(); // 确保连接始终被关闭
}
});
日志记录
记录脚本执行结束的状态:
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null) {
// 记录错误日志
file_put_contents('error.log',
date('Y-m-d H:i:s') . " - " .
json_encode($error) . "\n",
FILE_APPEND);
} else {
// 记录正常结束
file_put_contents('access.log',
date('Y-m-d H:i:s') . " - Ended successfully\n",
FILE_APPEND);
}
});
框架中的统一处理
在 MVC 框架中统一处理异常和错误:
// 在框架入口文件设置
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'], [
E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR
])) {
// 显示友好的错误页面
ob_clean(); // 清除之前的输出
http_response_code(500);
include 'views/errors/500.php';
}
});
执行顺序说明
echo "Start\n";
register_shutdown_function(function() {
echo "Shutdown 1\n";
});
register_shutdown_function(function() {
echo "Shutdown 2\n";
});
// 输出:
// Start
// Shutdown 2 ← 后注册的先执行(LIFO)
// Shutdown 1
与析构函数的区别
| 特性 | register_shutdown_function | 析构函数 (__destruct) |
|---|---|---|
| 执行时机 | 脚本结束前 | 对象销毁时 |
| 执行顺序 | 后注册先执行 | 按对象销毁顺序 |
| 捕获致命错误 | 能捕获 | 不能捕获 |
| 参数传递 | 可以传递参数 | 不能接收参数 |
实际项目示例
完整的错误处理系统
class ErrorHandler {
public function __construct() {
register_shutdown_function([$this, 'handleShutdown']);
}
public function handleShutdown() {
$error = error_get_last();
if ($error === null) {
return; // 正常结束
}
// 处理不同类型的错误
switch ($error['type']) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
$this->handleFatalError($error);
break;
}
}
private function handleFatalError($error) {
// 1. 记录错误到日志
error_log(sprintf(
"Fatal Error: %s in %s on line %d",
$error['message'],
$error['file'],
$error['line']
));
// 2. 发送错误通知(如邮件)
// $this->sendErrorNotification($error);
// 3. 显示用户友好界面
if (!headers_sent()) {
http_response_code(500);
header('Content-Type: text/html; charset=utf-8');
}
// 清空可能的部分输出
while (ob_get_level()) {
ob_end_clean();
}
echo "系统遇到意外错误,请稍后再试";
}
}
// 使用
$handler = new ErrorHandler();
性能监控
class PerformanceMonitor {
private $startTime;
public function __construct() {
$this->startTime = microtime(true);
register_shutdown_function([$this, 'logPerformance']);
}
public function logPerformance() {
$duration = microtime(true) - $this->startTime;
$memory = memory_get_peak_usage(true) / 1024 / 1024;
// 记录性能数据
error_log(sprintf(
"Page load: %.2f sec, Memory: %.2f MB",
$duration,
$memory
));
// 如果执行时间过长,发出警告
if ($duration > 2) {
error_log("Warning: Page load time exceeded 2 seconds");
}
}
}
// 在应用入口使用
$monitor = new PerformanceMonitor();
注意事项
-
HTTP 头已发送问题:在 shutdown 函数中如果还想发送 HTTP 头,需要先检查
headers_sent()状态 -
不能修改输出:如果使用了输出缓冲,可以在函数内操作缓冲区
-
多个函数顺序:多个注册的函数按 LIFO(后进先出)顺序执行
-
耗时操作:不要在 shutdown 函数中执行耗时操作,会影响用户体验
-
PHP 7+ 兼容:在 PHP 7 中,可以使用
Throwable接口捕获更多错误类型
最佳实践
// 推荐的通用设置
register_shutdown_function(function() {
$error = error_get_last();
if ($error && in_array($error['type'],
[E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])
) {
// 清理输出缓冲
while (ob_get_level()) {
ob_end_clean();
}
// 记录致命错误
error_log("FATAL: {$error['message']} in {$error['file']}:{$error['line']}");
// 返回错误响应
if (!headers_sent()) {
http_response_code(500);
header('Content-Type: application/json');
echo json_encode(['error' => 'Internal server error']);
}
}
});
register_shutdown_function 是构建健壮 PHP 应用的重要工具,特别是对错误处理和资源清理提供了最后的安全网。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播