PHP项目register_shutdown_function作用

wen PHP项目 3

本文目录导读:

PHP项目register_shutdown_function作用

  1. 核心作用
  2. 执行顺序说明
  3. 与析构函数的区别
  4. 实际项目示例
  5. 注意事项
  6. 最佳实践

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();

注意事项

  1. HTTP 头已发送问题:在 shutdown 函数中如果还想发送 HTTP 头,需要先检查 headers_sent() 状态

  2. 不能修改输出:如果使用了输出缓冲,可以在函数内操作缓冲区

  3. 多个函数顺序:多个注册的函数按 LIFO(后进先出)顺序执行

  4. 耗时操作:不要在 shutdown 函数中执行耗时操作,会影响用户体验

  5. 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 应用的重要工具,特别是对错误处理和资源清理提供了最后的安全网。

抱歉,评论功能暂时关闭!