libxml_clear_errors() 函数用于清除 libxml 错误缓冲区。当使用 libxml 库处理 XML 文档时(如通过 DOMDocument、SimpleXML 或 XMLReader),解析过程中产生的错误会存储在错误缓冲区中。此函数用于清空该缓冲区。
libxml_clear_errors ( ) : void
该函数没有参数。
该函数没有返回值(返回类型为 void)。
下面的示例演示在解析XML时如何使用 libxml_clear_errors() 清除错误缓冲区。
<?php
// 启用用户自定义错误处理
libxml_use_internal_errors(true);
// 创建一个格式错误的XML字符串
$malformed_xml = '<root><item>value1</item><item>value2<item></root>';
echo "<h4>解析格式错误的XML:</h4>";
echo "<pre>" . htmlspecialchars($malformed_xml) . "</pre>";
// 尝试解析格式错误的XML
$doc = new DOMDocument();
$result = $doc->loadXML($malformed_xml);
if (!$result) {
echo "<div class='alert alert-danger'>XML解析失败!</div>";
// 获取错误信息
$errors = libxml_get_errors();
echo "<h5>解析错误:</h5>";
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>级别</th><th>错误代码</th><th>消息</th><th>行号</th></tr></thead>";
echo "<tbody>";
foreach ($errors as $error) {
$level = '';
switch ($error->level) {
case LIBXML_ERR_WARNING: $level = '警告'; break;
case LIBXML_ERR_ERROR: $level = '错误'; break;
case LIBXML_ERR_FATAL: $level = '致命错误'; break;
default: $level = '未知'; break;
}
echo "<tr>";
echo "<td>$level</td>";
echo "<td>{$error->code}</td>";
echo "<td>" . htmlspecialchars($error->message) . "</td>";
echo "<td>{$error->line}</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 清除错误缓冲区
libxml_clear_errors();
echo "<div class='alert alert-success'>已清除错误缓冲区</div>";
// 验证错误是否已被清除
$remaining_errors = libxml_get_errors();
echo "<p>剩余错误数量: " . count($remaining_errors) . "</p>";
}
// 尝试解析另一个XML(之前的错误已清除)
echo "<hr><h4>尝试解析另一个XML:</h4>";
$another_xml = '<root><item>value1</item></root>';
$doc2 = new DOMDocument();
$result2 = $doc2->loadXML($another_xml);
if ($result2) {
echo "<div class='alert alert-success'>XML解析成功!</div>";
echo "<p>XML内容: " . htmlspecialchars($doc2->saveXML()) . "</p>";
}
?>
下面的示例演示在处理多个XML文件时如何及时清除错误,避免错误累积。
<?php
// 启用内部错误处理
libxml_use_internal_errors(true);
// 模拟多个XML文件数据
$xml_files = [
'file1' => '<root><item>正确XML</item></root>',
'file2' => '<root><item>value<item></root>', // 格式错误:缺少结束标签
'file3' => '<root><item attribute="value">内容</item></root>',
'file4' => '<root><item>特殊字符 & < > </item></root>',
'file5' => '<root>未闭合标签', // 严重的格式错误
];
echo "<h4>批量处理XML文件:</h4>";
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>文件</th><th>状态</th><th>错误信息</th></tr></thead>";
echo "<tbody>";
foreach ($xml_files as $filename => $xml_content) {
// 每次解析前清除之前的错误
libxml_clear_errors();
$doc = new DOMDocument();
$result = $doc->loadXML($xml_content);
if ($result) {
echo "<tr class='table-success'>";
echo "<td>$filename</td>";
echo "<td><span class='badge bg-success'>成功</span></td>";
echo "<td>无错误</td>";
echo "</tr>";
} else {
echo "<tr class='table-danger'>";
echo "<td>$filename</td>";
echo "<td><span class='badge bg-danger'>失败</span></td>";
// 获取并显示错误
$errors = libxml_get_errors();
$error_messages = [];
foreach ($errors as $error) {
// 截断过长的错误信息
$message = htmlspecialchars($error->message);
if (strlen($message) > 100) {
$message = substr($message, 0, 100) . '...';
}
$error_messages[] = "行 {$error->line}: $message";
}
echo "<td>" . implode('<br>', $error_messages) . "</td>";
echo "</tr>";
}
}
echo "</tbody></table>";
// 最后清除所有错误
libxml_clear_errors();
// 显示统计信息
$final_errors = libxml_get_errors();
echo "<div class='alert alert-info'>";
echo "处理完成。最终错误缓冲区大小: " . count($final_errors);
echo "</div>";
?>
下面的示例演示如何创建自定义错误处理函数并与 libxml_clear_errors() 结合使用。
<?php
/**
* 自定义XML错误处理类
*/
class XmlErrorHandler {
private $errors = [];
private $error_count = 0;
/**
* 处理XML解析错误
*/
public function handleXmlError($errno, $errstr, $errfile, $errline) {
$this->errors[] = [
'level' => $errno,
'message' => $errstr,
'file' => $errfile,
'line' => $errline,
'time' => time()
];
$this->error_count++;
}
/**
* 获取所有错误
*/
public function getErrors() {
return $this->errors;
}
/**
* 获取错误数量
*/
public function getErrorCount() {
return $this->error_count;
}
/**
* 清除错误记录
*/
public function clearErrors() {
$this->errors = [];
$this->error_count = 0;
}
/**
* 安全解析XML
*/
public function safeParseXml($xml_string, $filename = '') {
// 启用内部错误处理
libxml_use_internal_errors(true);
// 清除之前的libxml错误
libxml_clear_errors();
$doc = new DOMDocument();
// 尝试解析
$result = $doc->loadXML($xml_string);
if (!$result) {
// 获取libxml错误
$libxml_errors = libxml_get_errors();
// 将libxml错误转换为自定义格式
foreach ($libxml_errors as $error) {
$this->errors[] = [
'level' => $error->level,
'code' => $error->code,
'message' => trim($error->message),
'line' => $error->line,
'column' => $error->column,
'file' => $filename,
'time' => time()
];
$this->error_count++;
}
// 清除libxml错误缓冲区
libxml_clear_errors();
}
return $result ? $doc : false;
}
}
// 使用自定义错误处理器
$xml_handler = new XmlErrorHandler();
// 测试XML数据
$test_xmls = [
'正确XML' => '<?xml version="1.0" encoding="UTF-8"?><root><item id="1">测试内容</item></root>',
'格式错误XML' => '<root><item>未闭合标签</root>',
'编码问题XML' => '<root><item>特殊字符: & © €</item></root>'
];
echo "<h4>使用自定义错误处理器解析XML:</h4>";
foreach ($test_xmls as $name => $xml) {
echo "<h5>测试: $name</h5>";
// 清除之前的错误记录
$xml_handler->clearErrors();
$result = $xml_handler->safeParseXml($xml, $name);
if ($result) {
echo "<div class='alert alert-success mb-3'>解析成功</div>";
} else {
echo "<div class='alert alert-danger mb-3'>解析失败</div>";
$errors = $xml_handler->getErrors();
if (!empty($errors)) {
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>文件</th><th>错误级别</th><th>消息</th><th>行号</th></tr></thead>";
echo "<tbody>";
foreach ($errors as $error) {
$level = '';
switch ($error['level']) {
case LIBXML_ERR_WARNING: $level = '警告'; break;
case LIBXML_ERR_ERROR: $level = '错误'; break;
case LIBXML_ERR_FATAL: $level = '致命错误'; break;
default: $level = '未知'; break;
}
echo "<tr>";
echo "<td>{$error['file']}</td>";
echo "<td><span class='badge bg-danger'>$level</span></td>";
echo "<td>" . htmlspecialchars($error['message']) . "</td>";
echo "<td>{$error['line']}</td>";
echo "</tr>";
}
echo "</tbody></table>";
}
}
}
echo "<div class='alert alert-info mt-3'>";
echo "总错误数(所有测试): " . $xml_handler->getErrorCount();
echo "</div>";
?>
下面的示例演示在处理大量XML数据时,如何通过清除错误缓冲区来优化性能和管理内存。
<?php
/**
* 高性能XML批处理类
*/
class XmlBatchProcessor {
private $processed_count = 0;
private $error_count = 0;
private $success_count = 0;
/**
* 处理大量XML数据
*/
public function processBatch(array $xml_data_array, $options = []) {
// 启用内部错误处理
libxml_use_internal_errors(true);
$default_options = [
'validate' => false,
'memory_check' => true,
'chunk_size' => 100 // 每处理100个后清理错误缓冲区
];
$options = array_merge($default_options, $options);
$results = [];
$chunk_counter = 0;
foreach ($xml_data_array as $id => $xml_data) {
// 清除错误缓冲区(按块大小)
if ($chunk_counter % $options['chunk_size'] === 0) {
libxml_clear_errors();
if ($options['memory_check']) {
$this->logMemoryUsage("处理块开始 {$chunk_counter}");
}
}
$result = $this->processSingle($xml_data, $options);
$results[$id] = $result;
if ($result['success']) {
$this->success_count++;
} else {
$this->error_count++;
}
$this->processed_count++;
$chunk_counter++;
}
// 最后清理一次错误缓冲区
libxml_clear_errors();
return $results;
}
/**
* 处理单个XML
*/
private function processSingle($xml_data, $options) {
$result = [
'success' => false,
'errors' => [],
'data' => null
];
try {
$doc = new DOMDocument();
// 设置解析选项
if ($options['validate']) {
$doc->validateOnParse = true;
}
// 尝试解析
$parse_result = @$doc->loadXML($xml_data);
if ($parse_result) {
$result['success'] = true;
$result['data'] = $doc;
} else {
// 获取错误
$errors = libxml_get_errors();
foreach ($errors as $error) {
$result['errors'][] = [
'level' => $error->level,
'code' => $error->code,
'message' => trim($error->message),
'line' => $error->line
];
}
}
} catch (Exception $e) {
$result['errors'][] = [
'level' => 'EXCEPTION',
'message' => $e->getMessage()
];
}
return $result;
}
/**
* 记录内存使用情况
*/
private function logMemoryUsage($context) {
$memory = memory_get_usage(true);
$memory_mb = round($memory / 1024 / 1024, 2);
error_log("[$context] 内存使用: {$memory_mb} MB");
}
/**
* 获取统计信息
*/
public function getStats() {
return [
'processed' => $this->processed_count,
'success' => $this->success_count,
'errors' => $this->error_count
];
}
}
// 生成测试数据
$test_data = [];
for ($i = 0; $i < 250; $i++) {
if ($i % 10 === 0) {
// 每10个中有一个格式错误的XML
$test_data["xml_$i"] = '<root><item>未闭合标签</root>';
} else {
$test_data["xml_$i"] = "<?xml version=\"1.0\"?><root><item id=\"$i\">数据 $i</item></root>";
}
}
echo "<h4>高性能XML批处理演示:</h4>";
echo "<p>处理数据量: " . count($test_data) . " 个XML文档</p>";
// 启动处理器
$processor = new XmlBatchProcessor();
// 处理数据
$start_time = microtime(true);
$results = $processor->processBatch($test_data, ['chunk_size' => 50]);
$end_time = microtime(true);
$stats = $processor->getStats();
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>统计项</th><th>值</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>总处理数</td><td>{$stats['processed']}</td></tr>";
echo "<tr><td>成功数</td><td><span class='badge bg-success'>{$stats['success']}</span></td></tr>";
echo "<tr><td>失败数</td><td><span class='badge bg-danger'>{$stats['errors']}</span></td></tr>";
echo "<tr><td>处理时间</td><td>" . round(($end_time - $start_time) * 1000, 2) . " 毫秒</td></tr>";
echo "<tr><td>平均每个XML</td><td>" . round(($end_time - $start_time) * 1000 / count($test_data), 3) . " 毫秒</td></tr>";
echo "</tbody></table>";
// 显示部分结果
echo "<h5>部分处理结果:</h5>";
echo "<div class='table-responsive' style='max-height: 300px; overflow-y: auto;'>";
echo "<table class='table table-sm table-bordered'>";
echo "<thead><tr><th>ID</th><th>状态</th><th>错误数</th><th>错误示例</th></tr></thead>";
echo "<tbody>";
$counter = 0;
foreach ($results as $id => $result) {
if ($counter++ >= 15) break; // 只显示前15个结果
if ($result['success']) {
echo "<tr class='table-success'>";
echo "<td>$id</td>";
echo "<td><span class='badge bg-success'>成功</span></td>";
echo "<td>0</td>";
echo "<td>-</td>";
echo "</tr>";
} else {
echo "<tr class='table-danger'>";
echo "<td>$id</td>";
echo "<td><span class='badge bg-danger'>失败</span></td>";
echo "<td>" . count($result['errors']) . "</td>";
$error_sample = '';
if (!empty($result['errors'])) {
$first_error = $result['errors'][0];
$error_sample = htmlspecialchars(substr($first_error['message'], 0, 50)) . '...';
}
echo "<td>$error_sample</td>";
echo "</tr>";
}
}
echo "</tbody></table>";
echo "</div>";
echo "<div class='alert alert-info mt-3'>";
echo "<strong>性能优化说明:</strong>";
echo "<ul class='mb-0'>";
echo "<li>通过定期调用 <code>libxml_clear_errors()</code> 防止错误缓冲区无限增长</li>";
echo "<li>分块处理可以减少内存占用</li>";
echo "<li>及时清理错误可以避免内存泄漏</li>";
echo "</ul>";
echo "</div>";
?>
下面的示例演示 libxml_clear_errors() 与其他libxml函数如何配合工作。
<?php
/**
* 演示libxml相关函数的配合使用
*/
class LibXmlDemo {
/**
* 安全解析XML并获取详细信息
*/
public function safeParseWithDetails($xml_string) {
// 1. 启用内部错误处理
libxml_use_internal_errors(true);
// 2. 清除之前的错误(确保干净状态)
libxml_clear_errors();
// 3. 获取libxml版本信息
$version_info = $this->getLibXmlVersion();
echo "<h5>libxml版本信息:</h5>";
echo "<ul>";
echo "<li>版本: {$version_info['version']}</li>";
echo "<li>内部版本: {$version_info['internal_version']}</li>";
echo "<li>实体加载: " . ($version_info['entity_loader'] ? '启用' : '禁用') . "</li>";
echo "</ul>";
// 4. 禁用实体加载(安全考虑)
$old_entity_loader = libxml_disable_entity_loader(true);
// 5. 设置解析选项
$old_options = libxml_set_streams_context(stream_context_create([
'http' => ['timeout' => 5]
]));
// 6. 解析XML
$doc = new DOMDocument();
$result = $doc->loadXML($xml_string);
// 7. 获取错误统计
$error_stats = $this->getErrorStatistics();
echo "<h5>解析结果:</h5>";
if ($result) {
echo "<div class='alert alert-success'>解析成功</div>";
// 获取XML基本信息
$xml_info = [
'encoding' => $doc->encoding ?: '未指定',
'version' => $doc->xmlVersion ?: '未指定',
'根元素' => $doc->documentElement ? $doc->documentElement->tagName : '无'
];
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>属性</th><th>值</th></tr></thead>";
echo "<tbody>";
foreach ($xml_info as $key => $value) {
echo "<tr><td>$key</td><td>$value</td></tr>";
}
echo "</tbody></table>";
} else {
echo "<div class='alert alert-danger'>解析失败</div>";
}
echo "<h5>错误统计:</h5>";
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>错误级别</th><th>数量</th></tr></thead>";
echo "<tbody>";
foreach ($error_stats as $level => $count) {
echo "<tr><td>$level</td><td>$count</td></tr>";
}
echo "</tbody></table>";
// 8. 显示详细错误信息(如果有)
$errors = libxml_get_errors();
if (!empty($errors)) {
echo "<h5>详细错误信息:</h5>";
echo "<div style='max-height: 200px; overflow-y: auto;'>";
echo "<table class='table table-bordered table-sm'>";
echo "<thead><tr><th>级别</th><th>代码</th><th>消息</th><th>位置</th></tr></thead>";
echo "<tbody>";
foreach ($errors as $error) {
$level = $this->getErrorLevelName($error->level);
$position = "行: {$error->line}, 列: " . ($error->column ?: '未知');
echo "<tr>";
echo "<td><span class='badge bg-danger'>$level</span></td>";
echo "<td>{$error->code}</td>";
echo "<td>" . htmlspecialchars($error->message) . "</td>";
echo "<td>$position</td>";
echo "</tr>";
}
echo "</tbody></table>";
echo "</div>";
}
// 9. 清除错误缓冲区(清理)
libxml_clear_errors();
// 10. 恢复原始设置
libxml_disable_entity_loader($old_entity_loader);
return $result ? $doc : false;
}
/**
* 获取错误级别名称
*/
private function getErrorLevelName($level) {
$levels = [
LIBXML_ERR_WARNING => '警告',
LIBXML_ERR_ERROR => '错误',
LIBXML_ERR_FATAL => '致命错误'
];
return $levels[$level] ?? '未知级别';
}
/**
* 获取错误统计
*/
private function getErrorStatistics() {
$errors = libxml_get_errors();
$stats = ['警告' => 0, '错误' => 0, '致命错误' => 0];
foreach ($errors as $error) {
$level_name = $this->getErrorLevelName($error->level);
if (isset($stats[$level_name])) {
$stats[$level_name]++;
}
}
return $stats;
}
/**
* 获取libxml版本信息
*/
private function getLibXmlVersion() {
return [
'version' => LIBXML_VERSION,
'internal_version' => LIBXML_DOTTED_VERSION,
'entity_loader' => !libxml_disable_entity_loader()
];
}
}
// 测试数据
$test_xml = '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY test "测试实体">
]>
<root>
<item id="1">第一个项目</item>
<item id="2">第二个项目</item>
<item id="3">第三个项目 &test;</item>
<item>未闭合标签
</root>';
echo "<h4>libxml函数综合演示:</h4>";
$demo = new LibXmlDemo();
$result = $demo->safeParseWithDetails($test_xml);
echo "<div class='alert alert-info mt-3'>";
echo "<strong>相关libxml函数:</strong>";
echo "<ul class='mb-0'>";
echo "<li><code>libxml_use_internal_errors()</code> - 启用/禁用内部错误处理</li>";
echo "<li><code>libxml_get_errors()</code> - 获取错误数组</li>";
echo "<li><code>libxml_get_last_error()</code> - 获取最后一个错误</li>";
echo "<li><code>libxml_disable_entity_loader()</code> - 禁用外部实体加载(安全)</li>";
echo "<li><code>libxml_set_streams_context()</code> - 设置流上下文</li>";
echo "</ul>";
echo "</div>";
?>
libxml_clear_errors() 之前,通常需要先调用 libxml_use_internal_errors(true) 来启用内部错误处理模式。libxml_clear_errors() 之前使用 libxml_get_errors() 获取错误信息。