PHPerror_get_last()函数

简介

error_get_last() 是PHP内置的错误处理函数,用于获取最后发生的错误信息。它返回一个关联数组,包含最后一次错误的详细信息,包括错误类型、错误消息、发生错误的文件和行号。

这个函数在错误处理、日志记录和调试中非常有用,特别是在使用自定义错误处理器时,可以获取到最近发生的错误详情。
注意:error_get_last() 只返回脚本执行期间发生的最后一个错误。如果需要获取所有错误,需要使用自定义错误处理器。

语法

array|null error_get_last(void)

该函数不需要任何参数,返回最后发生的错误的详细信息数组,如果没有发生错误则返回 null

返回值

返回一个包含以下键的关联数组,如果没有错误发生则返回 null

键名 描述 示例值
type 错误类型(整数) 2 (E_WARNING), 8 (E_NOTICE), 256 (E_USER_ERROR) 等
message 错误消息 "Undefined variable: undefinedVar"
file 发生错误的文件名 "/var/www/html/test.php"
line 发生错误的行号 15
错误类型常量:
常量 描述 说明
E_ERROR 1 致命运行时错误 脚本终止执行的错误
E_WARNING 2 运行时警告 非致命错误,脚本继续执行
E_PARSE 4 编译时解析错误 语法解析错误
E_NOTICE 8 运行时通知 可能是错误也可能不是
E_CORE_ERROR 16 PHP初始化启动期间致命错误 PHP引擎启动时的致命错误
E_USER_ERROR 256 用户生成的错误 用户调用trigger_error()生成
E_USER_WARNING 512 用户生成的警告 用户调用trigger_error()生成
E_USER_NOTICE 1024 用户生成的通知 用户调用trigger_error()生成
E_STRICT 2048 运行时通知 PHP建议的代码修改
E_RECOVERABLE_ERROR 4096 可捕获的致命错误 可被错误处理器捕获的致命错误
E_ALL 32767 所有错误和警告 PHP 5.4之前是30719,之后是32767

示例

示例1:基本用法

演示如何获取和处理最后一个错误:

<?php
// 触发一个警告
echo $undefinedVariable;

// 获取最后一个错误
$lastError = error_get_last();

echo "<h4>最后错误信息:</h4>";
if ($lastError) {
    echo "<ul>";
    echo "<li>类型: " . $lastError['type'] . " (" . getErrorTypeName($lastError['type']) . ")</li>";
    echo "<li>消息: " . $lastError['message'] . "</li>";
    echo "<li>文件: " . $lastError['file'] . "</li>";
    echo "<li>行号: " . $lastError['line'] . "</li>";
    echo "</ul>";
} else {
    echo "没有错误发生";
}

// 辅助函数:将错误类型常量转换为可读名称
function getErrorTypeName($type) {
    $errorTypes = [
        1     => 'E_ERROR',
        2     => 'E_WARNING',
        4     => 'E_PARSE',
        8     => 'E_NOTICE',
        16    => 'E_CORE_ERROR',
        32    => 'E_CORE_WARNING',
        64    => 'E_COMPILE_ERROR',
        128   => 'E_COMPILE_WARNING',
        256   => 'E_USER_ERROR',
        512   => 'E_USER_WARNING',
        1024  => 'E_USER_NOTICE',
        2048  => 'E_STRICT',
        4096  => 'E_RECOVERABLE_ERROR',
        8192  => 'E_DEPRECATED',
        16384 => 'E_USER_DEPRECATED',
        32767 => 'E_ALL'
    ];

    return isset($errorTypes[$type]) ? $errorTypes[$type] : '未知类型';
}

示例2:在错误处理器中使用

结合set_error_handler()error_get_last()处理错误:

<?php
// 自定义错误处理器
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    // 记录错误到日志
    error_log("错误: [$errno] $errstr 在 $errfile 第 $errline 行");

    // 显示友好的错误信息
    echo "<div style='border: 1px solid #f00; background: #fee; padding: 10px; margin: 10px 0;'>";
    echo "<strong>系统发生了一个错误:</strong><br>";
    echo "错误信息: " . htmlspecialchars($errstr) . "<br>";
    echo "位置: $errfile 第 $errline 行";
    echo "</div>";

    // 返回true表示已处理错误,阻止PHP默认错误处理器执行
    return true;
}

// 设置自定义错误处理器
set_error_handler("customErrorHandler", E_ALL);

// 触发一些错误
echo $undefinedVar;  // 未定义变量警告
file_get_contents("non_existent_file.txt");  // 文件不存在警告
strpos();  // 缺少参数警告

// 获取最后一个错误的详细信息
$lastError = error_get_last();

echo "<h4>最后错误的详细信息:</h4>";
if ($lastError) {
    echo "<pre>" . print_r($lastError, true) . "</pre>";
}

// 恢复默认错误处理器
restore_error_handler();

示例3:在文件操作中记录错误

在文件操作失败时获取错误信息:

<?php
function safeFileRead($filename) {
    // 尝试读取文件
    $content = @file_get_contents($filename);

    if ($content === false) {
        // 文件读取失败,获取错误信息
        $error = error_get_last();

        // 记录到错误日志
        $errorMsg = isset($error['message']) ? $error['message'] : '未知错误';
        error_log("文件读取失败: $filename - $errorMsg");

        // 返回自定义错误信息
        return [
            'success' => false,
            'error' => '无法读取文件: ' . htmlspecialchars($errorMsg),
            'file' => $filename
        ];
    }

    return [
        'success' => true,
        'content' => $content
    ];
}

// 测试读取不存在的文件
$result = safeFileRead('non_existent_file.txt');

echo "<h4>文件读取结果:</h4>";
echo "<pre>" . print_r($result, true) . "</pre>";

// 获取最后一个错误
$lastError = error_get_last();
echo "<h4>最后错误:</h4>";
echo "<pre>" . print_r($lastError, true) . "</pre>";

示例4:数据库操作错误处理

在数据库操作中使用error_get_last()获取错误:

<?php
// 模拟数据库连接和查询
function executeQuery($sql) {
    // 模拟数据库查询失败
    if (strpos($sql, 'SELECT') !== false) {
        // 故意触发错误
        $result = false;

        if (!$result) {
            // 记录数据库错误
            $errorInfo = [
                'type' => 2, // E_WARNING
                'message' => "Query failed: " . htmlspecialchars($sql),
                'file' => __FILE__,
                'line' => __LINE__
            ];

            // 在实际应用中,这里可能会调用 error_log() 或记录到数据库错误日志
            error_log("数据库查询失败: " . $errorInfo['message']);

            return [
                'success' => false,
                'error' => $errorInfo['message']
            ];
        }
    }

    return [
        'success' => true,
        'data' => ['id' => 1, 'name' => '测试用户']
    ];
}

// 执行查询
$query = "SELECT * FROM users WHERE id = 999";
$result = executeQuery($query);

echo "<h4>查询结果:</h4>";
if (!$result['success']) {
    echo "<div style='color: red;'>错误: " . $result['error'] . "</div>";

    // 获取并显示最后错误
    $lastError = error_get_last();
    if ($lastError) {
        echo "<h4>系统最后错误:</h4>";
        echo "<pre>" . print_r($lastError, true) . "</pre>";
    }
} else {
    echo "<pre>" . print_r($result['data'], true) . "</pre>";
}

示例5:在异常处理中获取错误

在try-catch块中使用error_get_last()

<?php
// 设置自定义错误处理器
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    // 将错误转换为异常
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    // 触发一些错误
    echo $undefinedVariable;

} catch (ErrorException $e) {
    echo "<div style='border: 1px solid #f00; padding: 10px; background: #fee;'>";
    echo "<h4>捕获到异常:</h4>";
    echo "消息: " . $e->getMessage() . "<br>";
    echo "文件: " . $e->getFile() . "<br>";
    echo "行号: " . $e->getLine() . "<br>";
    echo "错误代码: " . $e->getCode() . "<br>";
    echo "</div>";

    // 使用 error_get_last() 获取错误信息
    $lastError = error_get_last();

    echo "<h4>通过 error_get_last() 获取:</h4>";
    if ($lastError) {
        echo "<ul>";
        foreach ($lastError as $key => $value) {
            echo "<li>$key: " . htmlspecialchars($value) . "</li>";
        }
        echo "</ul>";
    }
} finally {
    // 恢复错误处理器
    restore_error_handler();
}

示例6:错误日志记录器

创建一个完整的错误日志记录器:

<?php
class ErrorLogger {
    private $logFile;
    private $errors = [];

    public function __construct($logFile = 'error.log') {
        $this->logFile = $logFile;

        // 设置自定义错误处理器
        set_error_handler([$this, 'handleError']);

        // 设置自定义异常处理器
        set_exception_handler([$this, 'handleException']);

        // 设置关闭函数,在脚本结束时记录所有错误
        register_shutdown_function([$this, 'shutdownHandler']);
    }

    public function handleError($errno, $errstr, $errfile, $errline) {
        $error = [
            'type' => $errno,
            'message' => $errstr,
            'file' => $errfile,
            'line' => $errline,
            'timestamp' => date('Y-m-d H:i:s'),
            'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5)
        ];

        $this->errors[] = $error;

        // 记录到文件
        $this->logToFile($error);

        // 不阻止PHP默认错误处理器
        return false;
    }

    public function handleException($exception) {
        $error = [
            'type' => 'EXCEPTION',
            'message' => $exception->getMessage(),
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'timestamp' => date('Y-m-d H:i:s'),
            'backtrace' => $exception->getTrace()
        ];

        $this->errors[] = $error;
        $this->logToFile($error);
    }

    public function shutdownHandler() {
        // 获取最后的致命错误
        $lastError = error_get_last();

        if ($lastError && in_array($lastError['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
            $fatalError = [
                'type' => 'FATAL',
                'message' => $lastError['message'],
                'file' => $lastError['file'],
                'line' => $lastError['line'],
                'timestamp' => date('Y-m-d H:i:s')
            ];

            $this->errors[] = $fatalError;
            $this->logToFile($fatalError);

            // 在脚本结束时显示致命错误
            if (php_sapi_name() !== 'cli') {
                echo "<div style='background: #fdd; border: 2px solid red; padding: 15px; margin: 10px;'>";
                echo "<h3>致命错误</h3>";
                echo "<p>消息: " . htmlspecialchars($lastError['message']) . "</p>";
                echo "<p>位置: " . $lastError['file'] . " 第 " . $lastError['line'] . " 行</p>";
                echo "</div>";
            }
        }

        // 显示错误统计
        if (count($this->errors) > 0) {
            echo "<!-- 脚本执行期间发生了 " . count($this->errors) . " 个错误 -->";
        }
    }

    private function logToFile($error) {
        $logEntry = "[" . $error['timestamp'] . "] ";
        $logEntry .= "[" . $this->getErrorTypeName($error['type']) . "] ";
        $logEntry .= $error['message'] . " ";
        $logEntry .= "in " . $error['file'] . ":" . $error['line'] . PHP_EOL;

        file_put_contents($this->logFile, $logEntry, FILE_APPEND);
    }

    public function getErrors() {
        return $this->errors;
    }

    public function getLastError() {
        $lastError = error_get_last();
        if ($lastError) {
            $lastError['timestamp'] = date('Y-m-d H:i:s');
        }
        return $lastError;
    }

    private function getErrorTypeName($type) {
        $errorTypes = [
            1 => 'E_ERROR',
            2 => 'E_WARNING',
            4 => 'E_PARSE',
            8 => 'E_NOTICE',
            256 => 'E_USER_ERROR',
            512 => 'E_USER_WARNING',
            1024 => 'E_USER_NOTICE',
            'EXCEPTION' => 'EXCEPTION',
            'FATAL' => 'FATAL'
        ];

        return isset($errorTypes[$type]) ? $errorTypes[$type] : 'UNKNOWN';
    }
}

// 使用示例
$logger = new ErrorLogger('app_errors.log');

// 触发一些错误
echo $undefinedVar;  // 触发警告
strpos();  // 触发警告

// 获取最后错误
$lastError = $logger->getLastError();
echo "<h4>最后错误信息:</h4>";
echo "<pre>" . print_r($lastError, true) . "</pre>";

// 获取所有记录的错误
echo "<h4>所有记录的错误: (" . count($logger->getErrors()) . " 个)</h4>";
echo "<pre>" . print_r($logger->getErrors(), true) . "</pre>";

注意事项

重要提示:
  • 只返回最后一个错误:error_get_last() 只返回最近发生的错误信息。如果需要获取所有错误,需要使用自定义错误处理器。
  • 错误抑制操作符: 使用 @ 错误抑制操作符时,被抑制的错误不会被 error_get_last() 捕获。
  • 与 set_error_handler() 的关系: 即使设置了自定义错误处理器,error_get_last() 仍然可以获取到最后发生的错误。
  • 脚本结束时的错误: 在脚本结束时的致命错误可以通过 register_shutdown_function() 结合 error_get_last() 捕获。
  • 错误类型: 某些类型的错误(如语法错误、编译错误)可能无法被 error_get_last() 捕获。
  • 错误信息清理: 返回的错误信息可能包含文件系统路径等敏感信息,在生产环境中应谨慎处理。

实际应用场景

错误日志记录

在应用程序中记录最后一个错误信息,便于调试和问题追踪

优雅的错误处理

在自定义错误处理器中获取错误的详细信息,提供友好的用户界面

API错误响应

在API接口中返回详细的错误信息,便于客户端调试

使用技巧

技巧1:结合register_shutdown_function()捕获致命错误

致命错误(Fatal Error)无法被set_error_handler()捕获,但可以在register_shutdown_function()中使用error_get_last()获取:

<?php
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        // 处理致命错误
        error_log("致命错误: " . $error['message']);
    }
});
技巧2:在文件操作失败时获取详细错误

使用@抑制操作符结合error_get_last()获取文件操作失败的详细信息:

<?php
function safeFileOperation($filepath) {
    // 使用@抑制错误
    $result = @file_get_contents($filepath);

    if ($result === false) {
        $error = error_get_last();
        // 记录或处理错误
        return ['success' => false, 'error' => $error['message'] ?? '未知错误'];
    }

    return ['success' => true, 'content' => $result];
}
技巧3:创建调试信息收集器

在开发环境中收集错误信息用于调试:

<?php
class DebugCollector {
    private static $errors = [];

    public static function collect() {
        $error = error_get_last();
        if ($error) {
            self::$errors[] = [
                'error' => $error,
                'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS),
                'timestamp' => microtime(true)
            ];
        }
    }

    public static function getErrors() {
        return self::$errors;
    }
}

// 注册收集器
register_shutdown_function(['DebugCollector', 'collect']);