PHPerror_clear_last()函数

简介

error_clear_last() 是PHP内置的错误处理函数,用于清除最近一次发生的错误信息。这个函数是PHP 7.0.0版本新增的,用于清除error_get_last()返回的错误信息,使得后续调用error_get_last()时返回null

这个函数主要用于在需要精确控制错误处理流程的场景中,清除之前发生的错误状态,避免错误信息被后续代码误用。
注意:error_clear_last()只清除PHP内部存储的最后错误信息,不会影响自定义错误处理器或其他错误处理机制。

语法

void error_clear_last(void)

这个函数没有参数,也没有返回值。调用后,最后错误信息被清除。

返回值

void - 这个函数不返回任何值。

示例

示例1:基本用法

演示如何使用error_clear_last()清除最后错误:

<?php
echo "<h4>1. 触发错误并获取错误信息:</h4>";

// 触发一个错误
@$undefinedVariable;  // 使用@抑制错误,但错误仍会被记录

// 获取最后错误
$error = error_get_last();
if ($error !== null) {
    echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
    echo "<strong>最后错误信息:</strong><br>";
    echo "类型: " . $error['type'] . "<br>";
    echo "消息: " . htmlspecialchars($error['message']) . "<br>";
    echo "文件: " . $error['file'] . "<br>";
    echo "行号: " . $error['line'];
    echo "</div>";
} else {
    echo "没有错误发生";
}

echo "<h4>2. 清除最后错误:</h4>";
error_clear_last();

// 再次获取最后错误
$error = error_get_last();
if ($error !== null) {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "错误仍然存在: " . htmlspecialchars($error['message']);
    echo "</div>";
} else {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "✓ 错误已被成功清除";
    echo "</div>";
}

echo "<h4>3. 触发新错误:</h4>";
// 触发新错误
@file_get_contents('non_existent_file.txt');

// 获取新错误
$error = error_get_last();
if ($error !== null) {
    echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
    echo "<strong>新错误信息:</strong><br>";
    echo "消息: " . htmlspecialchars($error['message']);
    echo "</div>";
}

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

演示如何在自定义错误处理器中使用error_clear_last()

<?php
// 自定义错误处理器
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    echo "<div style='background:#f8f9fa; padding:10px; margin:5px; border:1px solid #ddd;'>";
    echo "<strong>自定义错误处理器捕获:</strong><br>";
    echo "错误: " . htmlspecialchars($errstr) . "<br>";
    echo "位置: " . $errfile . " 第 " . $errline . " 行";
    echo "</div>";

    // 清除最后错误
    error_clear_last();

    // 验证错误已被清除
    $clearedError = error_get_last();
    if ($clearedError === null) {
        echo "<div style='background:#d4edda; padding:5px; margin:5px; border:1px solid #c3e6cb; font-size:0.9em;'>";
        echo "✓ 错误已在处理器内部被清除";
        echo "</div>";
    }

    return true; // 阻止PHP默认处理器
});

echo "<h4>测试自定义错误处理器:</h4>";

// 触发错误
echo $undefinedVar;  // 会被自定义处理器捕获

// 在处理器外部检查错误
$externalError = error_get_last();
if ($externalError !== null) {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "处理器外部仍有错误: " . htmlspecialchars($externalError['message']);
    echo "</div>";
} else {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "✓ 处理器外部已无错误";
    echo "</div>";
}

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

echo "<h4>测试PHP默认错误处理器:</h4>";
// 再次触发错误(使用PHP默认处理器)
@$anotherUndefinedVar;

$error = error_get_last();
if ($error !== null) {
    echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
    echo "PHP默认处理器记录的错误: " . htmlspecialchars($error['message']);
    echo "</div>";

    // 清除这个错误
    error_clear_last();

    if (error_get_last() === null) {
        echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
        echo "✓ 默认处理器的错误已被清除";
        echo "</div>";
    }
}

示例3:在文件操作中使用

演示如何在文件操作中使用error_clear_last()处理错误:

<?php
// 安全的文件读取函数
function safeFileRead($filename) {
    // 清除之前的错误
    error_clear_last();

    // 尝试读取文件
    $content = @file_get_contents($filename);

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

        if ($error !== null) {
            // 记录错误但不抛出
            error_log("文件读取失败: {$filename} - {$error['message']}");

            // 清除错误,避免影响后续代码
            error_clear_last();

            return [
                'success' => false,
                'error' => "无法读取文件: " . htmlspecialchars($error['message']),
                'filename' => $filename
            ];
        } else {
            // 没有错误信息(可能是文件不存在但不产生错误)
            return [
                'success' => false,
                'error' => "文件不存在或无法访问: " . $filename,
                'filename' => $filename
            ];
        }
    }

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

echo "<h4>测试安全的文件读取:</h4>";

// 测试1:读取不存在的文件
$result1 = safeFileRead('non_existent_file.txt');
echo "<strong>测试1 - 不存在的文件:</strong><br>";
if (!$result1['success']) {
    echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
    echo "失败: " . $result1['error'];
    echo "</div>";
}

// 验证错误已被清除
$errorAfter1 = error_get_last();
if ($errorAfter1 === null) {
    echo "<div style='background:#d4edda; padding:5px; margin:5px; border:1px solid #c3e6cb; font-size:0.9em;'>";
    echo "✓ 错误已被清除";
    echo "</div>";
}

// 测试2:读取存在的文件(如果存在)
$testFile = 'test.txt';
file_put_contents($testFile, '测试内容');

$result2 = safeFileRead($testFile);
echo "<br><strong>测试2 - 存在的文件:</strong><br>";
if ($result2['success']) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "成功读取文件: " . $result2['filename'] . "<br>";
    echo "内容: " . htmlspecialchars($result2['content']);
    echo "</div>";
}

// 清理测试文件
if (file_exists($testFile)) {
    unlink($testFile);
}

// 测试3:连续操作
echo "<br><strong>测试3 - 连续操作:</strong><br>";

// 模拟一系列可能失败的操作
$operations = [
    ['file' => 'file1.txt', 'action' => '读取'],
    ['file' => 'file2.txt', 'action' => '读取'],
    ['file' => 'file3.txt', 'action' => '读取'],
];

foreach ($operations as $op) {
    // 每次操作前清除错误
    error_clear_last();

    $result = @file_get_contents($op['file']);

    if ($result === false) {
        $error = error_get_last();
        echo "<div style='background:#f8f9fa; padding:5px; margin:2px; border:1px solid #ddd;'>";
        echo "操作失败: {$op['action']} {$op['file']}";
        if ($error) {
            echo " - " . htmlspecialchars($error['message']);
        }
        echo "</div>";

        // 清除错误,避免影响下一个操作
        error_clear_last();
    } else {
        echo "<div style='background:#e7f3ff; padding:5px; margin:2px; border:1px solid #b3d7ff;'>";
        echo "操作成功: {$op['action']} {$op['file']}";
        echo "</div>";
    }
}

示例4:在数据库操作中使用

演示如何在数据库操作中使用error_clear_last()

<?php
// 模拟数据库操作类
class Database {
    private $connection;

    public function __construct($host, $username, $password, $database) {
        // 模拟连接
        $this->connection = [
            'host' => $host,
            'username' => $username,
            'database' => $database,
            'connected' => true
        ];
    }

    public function query($sql) {
        // 清除之前的错误
        error_clear_last();

        // 模拟查询,可能失败
        if (strpos($sql, 'ERROR') !== false) {
            // 触发错误
            trigger_error("SQL查询错误: 语法错误", E_USER_WARNING);

            // 获取错误
            $error = error_get_last();

            if ($error) {
                // 记录错误
                error_log("数据库查询失败: " . $error['message']);

                // 清除错误
                error_clear_last();

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

        // 模拟成功查询
        return [
            'success' => true,
            'data' => ['id' => 1, 'name' => '测试数据'],
            'sql' => $sql
        ];
    }

    public function execute($sql) {
        // 清除之前的错误
        error_clear_last();

        try {
            // 模拟执行
            if (strpos($sql, 'INSERT') !== false && strpos($sql, 'INVALID') !== false) {
                throw new Exception("插入失败: 违反唯一约束");
            }

            // 模拟成功
            $rowCount = rand(1, 10);

            return [
                'success' => true,
                'rowCount' => $rowCount,
                'sql' => $sql
            ];

        } catch (Exception $e) {
            // 记录异常但不抛出
            error_log("数据库执行异常: " . $e->getMessage());

            // 清除可能存在的错误
            error_clear_last();

            return [
                'success' => false,
                'error' => $e->getMessage(),
                'sql' => $sql
            ];
        }
    }

    public function getLastError() {
        $error = error_get_last();
        if ($error) {
            // 获取后清除
            error_clear_last();
            return $error['message'];
        }
        return null;
    }
}

// 使用示例
echo "<h4>测试数据库操作错误处理:</h4>";

$db = new Database('localhost', 'root', '', 'test_db');

// 测试1:成功的查询
echo "<strong>测试1 - 成功查询:</strong><br>";
$result1 = $db->query("SELECT * FROM users");
if ($result1['success']) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "查询成功: " . $result1['sql'] . "<br>";
    echo "数据: " . print_r($result1['data'], true);
    echo "</div>";
}

// 检查是否有错误遗留
$errorAfter1 = $db->getLastError();
if ($errorAfter1 === null) {
    echo "<div style='background:#d4edda; padding:5px; margin:5px; border:1px solid #c3e6cb; font-size:0.9em;'>";
    echo "✓ 无错误遗留";
    echo "</div>";
}

// 测试2:失败的查询
echo "<br><strong>测试2 - 失败查询:</strong><br>";
$result2 = $db->query("SELECT * FROM users WHERE ERROR");
if (!$result2['success']) {
    echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
    echo "查询失败: " . $result2['error'] . "<br>";
    echo "SQL: " . $result2['sql'];
    echo "</div>";
}

// 检查错误是否被清除
$errorAfter2 = $db->getLastError();
if ($errorAfter2 === null) {
    echo "<div style='background:#d4edda; padding:5px; margin:5px; border:1px solid #c3e6cb; font-size:0.9em;'>";
    echo "✓ 错误已被清除";
    echo "</div>";
}

// 测试3:执行操作
echo "<br><strong>测试3 - 执行操作:</strong><br>";
$result3 = $db->execute("INSERT INTO users (name) VALUES ('test')");
if ($result3['success']) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "执行成功,影响行数: " . $result3['rowCount'];
    echo "</div>";
}

// 测试4:失败的操作
echo "<br><strong>测试4 - 失败的操作:</strong><br>";
$result4 = $db->execute("INSERT INTO users (name) VALUES ('INVALID')");
if (!$result4['success']) {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "执行失败: " . $result4['error'];
    echo "</div>";
}

// 验证所有错误都被清除
echo "<br><strong>最终错误状态检查:</strong><br>";
$finalError = error_get_last();
if ($finalError === null) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "✓ 所有错误已被正确清除";
    echo "</div>";
} else {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "✗ 仍有未清除的错误: " . htmlspecialchars($finalError['message']);
    echo "</div>";
}

示例5:错误处理工具类

创建一个使用error_clear_last()的错误处理工具类:

<?php
/**
 * 错误处理工具类
 */
class ErrorHandler {
    private static $errors = [];
    private static $enabled = true;

    /**
     * 启用/禁用错误处理
     */
    public static function enable($enabled = true) {
        self::$enabled = $enabled;
    }

    /**
     * 执行操作并捕获错误
     */
    public static function capture($callback, $cleanAfter = true) {
        if (!self::$enabled) {
            return $callback();
        }

        // 清除之前的错误
        error_clear_last();

        try {
            $result = $callback();

            // 检查是否有错误发生
            $error = error_get_last();
            if ($error !== null) {
                self::recordError($error);

                if ($cleanAfter) {
                    error_clear_last();
                }
            }

            return $result;

        } catch (Exception $e) {
            // 记录异常
            self::recordException($e);
            throw $e;
        }
    }

    /**
     * 安全执行操作(不抛出异常)
     */
    public static function safeExecute($callback, $default = null) {
        try {
            return self::capture($callback);
        } catch (Exception $e) {
            return $default;
        }
    }

    /**
     * 获取并清除所有记录的错误
     */
    public static function getAndClearErrors() {
        $errors = self::$errors;
        self::$errors = [];
        return $errors;
    }

    /**
     * 清除所有错误
     */
    public static function clearAll() {
        self::$errors = [];
        error_clear_last();
    }

    /**
     * 检查是否有错误发生
     */
    public static function hasErrors() {
        return !empty(self::$errors) || error_get_last() !== null;
    }

    /**
     * 获取最后错误并清除
     */
    public static function getLastErrorAndClear() {
        $error = error_get_last();
        if ($error !== null) {
            error_clear_last();
        }
        return $error;
    }

    /**
     * 记录错误
     */
    private static function recordError($error) {
        $error['timestamp'] = date('Y-m-d H:i:s');
        $error['type_name'] = self::getErrorTypeName($error['type']);
        self::$errors[] = $error;
    }

    /**
     * 记录异常
     */
    private static function recordException($exception) {
        $error = [
            'type' => E_ERROR,
            'type_name' => 'EXCEPTION',
            'message' => $exception->getMessage(),
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'timestamp' => date('Y-m-d H:i:s'),
            'exception' => get_class($exception)
        ];
        self::$errors[] = $error;
    }

    /**
     * 获取错误类型名称
     */
    private static function getErrorTypeName($type) {
        $types = [
            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'
        ];

        return isset($types[$type]) ? $types[$type] : "UNKNOWN($type)";
    }
}

// 使用示例
echo "<h4>使用ErrorHandler工具类:</h4>";

// 启用错误处理
ErrorHandler::enable(true);

// 测试1:捕获错误
echo "<strong>测试1 - 捕获错误:</strong><br>";

$result1 = ErrorHandler::capture(function() {
    // 触发错误
    @$undefinedVariable;
    return "操作完成";
});

echo "结果: " . $result1 . "<br>";

// 检查是否有错误
if (ErrorHandler::hasErrors()) {
    $errors = ErrorHandler::getAndClearErrors();
    echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
    echo "捕获到 " . count($errors) . " 个错误:<br>";
    foreach ($errors as $error) {
        echo "• [" . $error['type_name'] . "] " . htmlspecialchars($error['message']) . "<br>";
    }
    echo "</div>";
}

// 测试2:安全执行
echo "<br><strong>测试2 - 安全执行:</strong><br>";

$result2 = ErrorHandler::safeExecute(function() {
    // 可能失败的操作
    $content = @file_get_contents('non_existent_file.txt');
    if ($content === false) {
        return false;
    }
    return $content;
}, "默认值");

echo "安全执行结果: " . var_export($result2, true) . "<br>";

// 测试3:连续操作
echo "<br><strong>测试3 - 连续操作:</strong><br>";

$operations = [
    '读取文件A' => function() { return @file_get_contents('file_a.txt'); },
    '数学计算' => function() { return 10 / 0; }, // 会触发警告
    '读取文件B' => function() { return @file_get_contents('file_b.txt'); },
];

foreach ($operations as $name => $callback) {
    ErrorHandler::clearAll(); // 清除之前的所有错误

    $result = ErrorHandler::safeExecute($callback, "操作失败");

    echo "操作: " . $name . " - 结果: " . var_export($result, true);

    if (ErrorHandler::hasErrors()) {
        echo " (有错误)";
    }

    echo "<br>";
}

// 测试4:获取并清除最后错误
echo "<br><strong>测试4 - 获取并清除最后错误:</strong><br>";

// 触发错误
@$undefinedVar;

$lastError = ErrorHandler::getLastErrorAndClear();
if ($lastError !== null) {
    echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
    echo "最后错误: " . htmlspecialchars($lastError['message']);
    echo "</div>";
}

// 验证错误已被清除
if (!ErrorHandler::hasErrors()) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "✓ 错误已被清除";
    echo "</div>";
}

示例6:实际应用场景

演示在实际应用场景中如何使用error_clear_last()

<?php
// API客户端类
class ApiClient {
    private $apiKey;
    private $baseUrl;
    private $lastError = null;

    public function __construct($apiKey, $baseUrl) {
        $this->apiKey = $apiKey;
        $this->baseUrl = rtrim($baseUrl, '/');
    }

    /**
     * 发送API请求
     */
    public function request($endpoint, $data = [], $method = 'GET') {
        // 清除之前的错误
        error_clear_last();
        $this->lastError = null;

        $url = $this->baseUrl . '/' . ltrim($endpoint, '/');
        $headers = [
            'Authorization: Bearer ' . $this->apiKey,
            'Content-Type: application/json',
        ];

        $options = [
            'http' => [
                'method' => $method,
                'header' => implode("\r\n", $headers),
                'ignore_errors' => true, // 不失败时抛出错误
            ]
        ];

        if ($method === 'POST' || $method === 'PUT') {
            $options['http']['content'] = json_encode($data);
        }

        $context = stream_context_create($options);

        // 发送请求
        $response = @file_get_contents($url, false, $context);

        if ($response === false) {
            // 获取错误信息
            $error = error_get_last();

            if ($error) {
                $this->lastError = [
                    'message' => $error['message'],
                    'code' => 0,
                    'timestamp' => date('Y-m-d H:i:s')
                ];

                // 清除错误
                error_clear_last();

                return [
                    'success' => false,
                    'error' => '请求失败: ' . $error['message'],
                    'status' => 0
                ];
            } else {
                return [
                    'success' => false,
                    'error' => '未知请求错误',
                    'status' => 0
                ];
            }
        }

        // 解析响应
        $data = json_decode($response, true);
        $statusCode = $this->getHttpStatusCode($http_response_header ?? []);

        if ($statusCode >= 200 && $statusCode < 300) {
            return [
                'success' => true,
                'data' => $data,
                'status' => $statusCode
            ];
        } else {
            $this->lastError = [
                'message' => $data['message'] ?? 'API请求失败',
                'code' => $statusCode,
                'timestamp' => date('Y-m-d H:i:s')
            ];

            return [
                'success' => false,
                'error' => $data['message'] ?? 'API请求失败',
                'status' => $statusCode,
                'data' => $data
            ];
        }
    }

    /**
     * 获取最后错误
     */
    public function getLastError() {
        $error = $this->lastError;
        $this->lastError = null; // 获取后清除
        return $error;
    }

    /**
     * 从响应头获取HTTP状态码
     */
    private function getHttpStatusCode($headers) {
        if (!empty($headers) && preg_match('/HTTP\/\d\.\d\s+(\d+)/', $headers[0], $matches)) {
            return (int)$matches[1];
        }
        return 0;
    }

    /**
     * 批量请求
     */
    public function batchRequest($requests) {
        $results = [];

        foreach ($requests as $index => $request) {
            // 清除之前的错误
            error_clear_last();

            $result = $this->request(
                $request['endpoint'],
                $request['data'] ?? [],
                $request['method'] ?? 'GET'
            );

            $results[$index] = $result;

            // 如果有错误,记录但不中断
            if (!$result['success']) {
                error_log("API请求失败 [{$index}]: " . $result['error']);
            }
        }

        return $results;
    }
}

// 使用示例
echo "<h4>API客户端错误处理示例:</h4>";

// 创建API客户端
$client = new ApiClient('test_key', 'https://api.example.com');

// 测试1:单个请求
echo "<strong>测试1 - 单个请求:</strong><br>";
$result1 = $client->request('/users/1');
if ($result1['success']) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "请求成功,状态码: " . $result1['status'];
    echo "</div>";
} else {
    echo "<div style='background:#fff3cd; padding:10px; margin:5px; border:1px solid #ffeaa7;'>";
    echo "请求失败: " . $result1['error'] . " (状态码: " . $result1['status'] . ")";
    echo "</div>";
}

// 获取错误
$error1 = $client->getLastError();
if ($error1 !== null) {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "最后错误: " . $error1['message'] . " (代码: " . $error1['code'] . ")";
    echo "</div>";
} else {
    echo "<div style='background:#e7f3ff; padding:10px; margin:5px; border:1px solid #b3d7ff;'>";
    echo "无错误记录";
    echo "</div>";
}

// 测试2:批量请求
echo "<br><strong>测试2 - 批量请求:</strong><br>";

$requests = [
    'user1' => ['endpoint' => '/users/1', 'method' => 'GET'],
    'user2' => ['endpoint' => '/users/2', 'method' => 'GET'],
    'invalid' => ['endpoint' => '/invalid-endpoint', 'method' => 'GET'],
    'create' => ['endpoint' => '/users', 'method' => 'POST', 'data' => ['name' => 'Test']],
];

$results = $client->batchRequest($requests);

$successCount = 0;
$failureCount = 0;

foreach ($results as $key => $result) {
    if ($result['success']) {
        $successCount++;
        echo "<div style='background:#d4edda; padding:5px; margin:2px; border:1px solid #c3e6cb; font-size:0.9em;'>";
        echo "✓ {$key}: 成功";
        echo "</div>";
    } else {
        $failureCount++;
        echo "<div style='background:#f8d7da; padding:5px; margin:2px; border:1px solid #f5c6cb; font-size:0.9em;'>";
        echo "✗ {$key}: 失败 - " . $result['error'];
        echo "</div>";
    }
}

echo "<div style='background:#f8f9fa; padding:10px; margin:5px; border:1px solid #ddd;'>";
echo "批量请求结果: 成功 {$successCount} 个,失败 {$failureCount} 个";
echo "</div>";

// 检查全局错误状态
echo "<br><strong>全局错误状态检查:</strong><br>";
$globalError = error_get_last();
if ($globalError === null) {
    echo "<div style='background:#d4edda; padding:10px; margin:5px; border:1px solid #c3e6cb;'>";
    echo "✓ 全局错误状态已清理";
    echo "</div>";
} else {
    echo "<div style='background:#f8d7da; padding:10px; margin:5px; border:1px solid #f5c6cb;'>";
    echo "✗ 有未清理的错误: " . htmlspecialchars($globalError['message']);
    echo "</div>";
}

常见问题

error_clear_last()清除的是error_get_last()返回的错误信息。这个错误信息是PHP内部记录的最后一次发生的错误,包括:

  • 由PHP触发的错误(E_ERROR, E_WARNING, E_NOTICE等)
  • trigger_error()user_error()触发的用户错误
  • 某些扩展(如文件操作、数据库操作)产生的错误

注意:error_clear_last()不会清除自定义错误处理器中记录的错误,也不会影响异常。

在以下情况下应该使用error_clear_last()

  1. 精确控制错误状态:在需要精确知道是否有新错误发生时,先清除之前的错误
  2. 避免错误信息污染:在进行一系列可能失败的操作时,每次操作前清除之前的错误
  3. 错误隔离:确保一个操作的错误不会影响另一个操作的错误检测
  4. 资源清理:在错误处理完成后,清理错误状态避免内存泄漏
  5. 测试和调试:在单元测试中,清除错误状态以确保测试的独立性

示例:

// 操作前清除错误
error_clear_last();

// 执行可能失败的操作
$result = @some_operation();

// 检查是否有新错误
if (error_get_last() !== null) {
    // 处理错误
    handle_error(error_get_last());
    error_clear_last(); // 处理完成后清除
}

error_clear_last()不会直接影响自定义错误处理器,但会影响自定义错误处理器通过error_get_last()获取的错误信息。

示例:

set_error_handler(function($errno, $errstr) {
    // 在错误处理器中,error_get_last()可能返回null
    $lastError = error_get_last();

    if ($lastError !== null) {
        echo "错误处理器中的错误: " . $lastError['message'];
        error_clear_last(); // 清除错误
    }

    return true;
});

// 触发错误
@$undefinedVar;

// 此时error_get_last()返回null
$error = error_get_last(); // null

自定义错误处理器仍然会被调用,但如果在处理器中清除了错误,后续代码通过error_get_last()就获取不到错误信息了。

error_clear_last()@错误抑制符有不同的作用:

  • @错误抑制符:临时抑制错误的显示,但错误仍然会被error_get_last()捕获
  • error_clear_last():清除error_get_last()返回的错误信息

它们可以结合使用:

// 使用@抑制错误显示
@$undefinedVar;

// 错误仍然存在
$error1 = error_get_last(); // 有错误信息

// 清除错误
error_clear_last();

// 错误被清除
$error2 = error_get_last(); // null

// 不使用@,直接清除
$undefinedVar; // 显示错误
error_clear_last(); // 清除错误,但错误已显示

$error3 = error_get_last(); // null,但用户已看到错误

最佳实践是:如果不想显示错误但需要知道是否发生错误,使用@配合error_get_last()error_clear_last()

error_clear_last()的性能影响可以忽略不计。它只是清除PHP内部的一个变量,操作非常快。

然而,过度使用可能会影响代码可读性。建议在以下情况下使用:

  1. 必要的时候:确实需要清除错误状态时
  2. 关键路径:在性能敏感的代码路径中,避免不必要的清除
  3. 错误隔离:在需要确保错误不交叉污染时

示例:合理的用法

// 好的用法:在循环中隔离每次迭代的错误
foreach ($items as $item) {
    error_clear_last(); // 清除上一次迭代的错误
    $result = processItem($item);

    if (error_get_last() !== null) {
        handleError($item, error_get_last());
        error_clear_last();
    }
}

// 不好的用法:过度清除
function process() {
    error_clear_last(); // 不一定需要
    step1();
    error_clear_last(); // 不一定需要
    step2();
    error_clear_last(); // 不一定需要
    step3();
}

一般来说,只在确实需要隔离错误状态时使用error_clear_last()

最佳实践

在操作前清除错误

在进行可能失败的操作前清除错误,确保只检测当前操作的错误:

function safeOperation() {
    // 清除之前的错误
    error_clear_last();

    // 执行可能失败的操作
    $result = @file_get_contents('file.txt');

    if ($result === false) {
        // 获取当前操作的错误
        $error = error_get_last();
        if ($error) {
            // 处理错误
            handleError($error);
            error_clear_last(); // 处理完成后清除
        }
    }

    return $result;
}
在循环中隔离错误

在处理多个项目时,每次迭代前清除错误,避免错误累积:

function processItems($items) {
    $results = [];
    $errors = [];

    foreach ($items as $item) {
        // 清除上一次迭代的错误
        error_clear_last();

        $result = processItem($item);

        // 检查本次迭代是否有错误
        $error = error_get_last();
        if ($error !== null) {
            $errors[] = [
                'item' => $item,
                'error' => $error
            ];
            error_clear_last(); // 清除以进行下一次迭代
        } else {
            $results[] = $result;
        }
    }

    return ['results' => $results, 'errors' => $errors];
}
结合@错误抑制符使用

使用@抑制错误显示,配合error_get_last()error_clear_last()进行精确错误处理:

function tryOperation() {
    // 抑制错误显示
    $result = @some_operation();

    if ($result === false) {
        $error = error_get_last();
        if ($error) {
            // 记录错误但不显示
            error_log("操作失败: " . $error['message']);
            error_clear_last(); // 清除错误
        }

        return false;
    }

    return $result;
}
创建错误处理包装函数

创建包装函数统一处理错误清除逻辑:

function withErrorClearing($callback) {
    // 清除之前的错误
    error_clear_last();

    try {
        $result = $callback();

        // 检查是否有错误
        $error = error_get_last();
        if ($error) {
            // 记录但不清除,让调用者决定
            return [
                'success' => false,
                'error' => $error,
                'result' => null
            ];
        }

        return [
            'success' => true,
            'error' => null,
            'result' => $result
        ];
    } catch (Exception $e) {
        error_clear_last(); // 清除可能的错误
        throw $e;
    }
}

// 使用
$result = withErrorClearing(function() {
    return @file_get_contents('file.txt');
});

总结

error_clear_last()是PHP 7.0.0引入的错误处理函数,用于清除error_get_last()返回的最后错误信息。

关键要点:

  • error_clear_last()清除PHP内部记录的最后错误
  • 通常与error_get_last()配合使用
  • 不会影响自定义错误处理器,但会影响error_get_last()的返回值
  • 在需要精确控制错误状态、隔离错误时使用
  • @错误抑制符结合使用可以实现静默错误处理
  • 性能影响可以忽略不计,但应避免过度使用

适用场景:文件操作、数据库操作、API调用、批量处理、错误隔离等需要精确错误处理的场景。