libxml_get_last_error() 函数用于获取最后一个 libxml 错误。与 libxml_get_errors() 返回所有错误数组不同,此函数只返回最近发生的单个错误。
libxml_use_internal_errors(true) 启用内部错误处理模式。
libxml_get_last_error ( ) : LibXMLError|false
该函数没有参数。
函数返回一个 LibXMLError 对象,如果没有错误发生则返回 FALSE。
LibXMLError 对象包含以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
level |
int | 错误级别:LIBXML_ERR_WARNING、LIBXML_ERR_ERROR、LIBXML_ERR_FATAL |
code |
int | 错误代码 |
column |
int | 发生错误的列号(如果可用) |
message |
string | 错误消息文本 |
file |
string | 文件名(如果解析的是文件) |
line |
int | 发生错误的行号 |
LIBXML_ERR_WARNING (1) - 警告,不影响解析但可能有潜在问题LIBXML_ERR_ERROR (2) - 错误,文档不符合规范但可能被解析LIBXML_ERR_FATAL (3) - 致命错误,文档无法解析下面的示例演示如何使用 libxml_get_last_error() 获取最后一个XML解析错误。
<?php
// 启用内部错误处理
libxml_use_internal_errors(true);
// 清除之前的错误
libxml_clear_errors();
// 创建一个格式错误的XML
$malformed_xml = '<root>
<item>第一个项目</item>
<item>第二个项目<item> <!-- 缺少结束标签 -->
<item attribute="value">第三个项目</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>";
// 获取最后一个错误
$last_error = libxml_get_last_error();
if ($last_error !== false) {
echo "<h5>最后一个错误信息:</h5>";
// 错误级别
$level = '';
switch ($last_error->level) {
case LIBXML_ERR_WARNING: $level = '警告'; break;
case LIBXML_ERR_ERROR: $level = '错误'; break;
case LIBXML_ERR_FATAL: $level = '致命错误'; break;
default: $level = '未知级别'; break;
}
echo "<div class='card" . ($last_error->level === LIBXML_ERR_FATAL ? ' border-danger' : ' border-warning') . "'>";
echo "<div class='card-header" . ($last_error->level === LIBXML_ERR_FATAL ? ' bg-danger text-white' : ' bg-warning') . "'>";
echo "最后错误 - $level (代码: {$last_error->code})";
echo "</div>";
echo "<div class='card-body'>";
echo "<p class='card-text'><strong>错误消息:</strong> " . htmlspecialchars(trim($last_error->message)) . "</p>";
echo "<p class='card-text'><strong>位置:</strong> 行 {$last_error->line}, 列 " . ($last_error->column ?: '未知') . "</p>";
echo "</div></div>";
// 显示所有错误数量作为对比
$all_errors = libxml_get_errors();
echo "<p class='mt-3'>总错误数: " . count($all_errors) . " (最后一个错误如上)</p>";
} else {
echo "<div class='alert alert-info'>没有获取到错误信息</div>";
}
// 清除错误缓冲区
libxml_clear_errors();
} else {
echo "<div class='alert alert-success'>XML解析成功!</div>";
}
?>
下面的示例演示 libxml_get_last_error() 和 libxml_get_errors() 的区别。
<?php
// 启用内部错误处理
libxml_use_internal_errors(true);
// 清除之前的错误
libxml_clear_errors();
// 创建一个包含多个错误的XML
$multi_error_xml = '<?xml version="1.0"?>
<root>
<item>项目1</item>
<item>项目2<item> <!-- 错误1:缺少结束标签 -->
<item attribute=value>项目3</item> <!-- 错误2:属性值缺少引号 -->
<item>项目4</item>
</root>';
echo "<h4>解析包含多个错误的XML:</h4>";
echo "<pre>" . htmlspecialchars($multi_error_xml) . "</pre>";
// 尝试解析XML
$doc = new DOMDocument();
$result = $doc->loadXML($multi_error_xml);
if (!$result) {
echo "<div class='alert alert-danger'>XML解析失败!</div>";
echo "<div class='row'>";
// 左边:显示所有错误
echo "<div class='col-md-6'>";
echo "<h5>libxml_get_errors() - 所有错误</h5>";
$all_errors = libxml_get_errors();
echo "<p>错误总数: " . count($all_errors) . "</p>";
if (!empty($all_errors)) {
echo "<table class='table table-sm table-bordered'>";
echo "<thead><tr><th>#</th><th>级别</th><th>错误消息</th><th>行号</th></tr></thead>";
echo "<tbody>";
foreach ($all_errors as $index => $error) {
$level = $error->level === LIBXML_ERR_WARNING ? '警告' :
($error->level === LIBXML_ERR_ERROR ? '错误' : '致命错误');
echo "<tr" . ($index === count($all_errors) - 1 ? " class='table-warning'" : "") . ">";
echo "<td>" . ($index + 1) . "</td>";
echo "<td><span class='badge " . ($level === '致命错误' ? 'bg-danger' : ($level === '错误' ? 'bg-warning' : 'bg-info')) . "'>$level</span></td>";
$message = trim($error->message);
if (strlen($message) > 50) {
$message = substr($message, 0, 50) . '...';
}
echo "<td>" . htmlspecialchars($message) . "</td>";
echo "<td>{$error->line}</td>";
echo "</tr>";
}
echo "</tbody></table>";
}
echo "</div>";
// 右边:显示最后一个错误
echo "<div class='col-md-6'>";
echo "<h5>libxml_get_last_error() - 最后一个错误</h5>";
$last_error = libxml_get_last_error();
if ($last_error !== false) {
$level = $last_error->level === LIBXML_ERR_WARNING ? '警告' :
($last_error->level === LIBXML_ERR_ERROR ? '错误' : '致命错误');
echo "<div class='card border-warning'>";
echo "<div class='card-header bg-warning'>";
echo "最后一个错误 - $level (代码: {$last_error->code})";
echo "</div>";
echo "<div class='card-body'>";
echo "<p class='card-text'><strong>错误消息:</strong> " . htmlspecialchars(trim($last_error->message)) . "</p>";
echo "<p class='card-text'><strong>位置:</strong> 行 {$last_error->line}, 列 " . ($last_error->column ?: '未知') . "</p>";
echo "<p class='card-text'><strong>错误顺序:</strong> 这是第 " . count($all_errors) . " 个(最后一个)错误</p>";
echo "</div></div>";
} else {
echo "<div class='alert alert-info'>没有获取到错误信息</div>";
}
echo "</div>";
echo "</div>"; // 结束row
// 比较说明
echo "<div class='alert alert-info mt-3'>";
echo "<h6>两个函数的区别:</h6>";
echo "<table class='table table-sm'>";
echo "<tr><th>函数</th><th>返回值</th><th>适用场景</th></tr>";
echo "<tr><td>libxml_get_errors()</td><td>错误数组</td><td>需要分析所有错误、统计错误类型、显示错误列表</td></tr>";
echo "<tr><td>libxml_get_last_error()</td><td>单个错误对象</td><td>快速检查是否有错误、记录最后错误、简单错误处理</td></tr>";
echo "</table>";
echo "</div>";
// 清除错误缓冲区
libxml_clear_errors();
}
?>
下面的示例演示如何使用 libxml_get_last_error() 进行简单的错误检查和日志记录。
<?php
/**
* 简单的XML解析器,使用libxml_get_last_error()进行错误处理
*/
class SimpleXmlParser {
/**
* 解析XML字符串,返回解析结果和错误信息
*/
public function parseXml($xml_string, $source_name = '') {
// 启用内部错误处理
libxml_use_internal_errors(true);
// 清除之前的错误
libxml_clear_errors();
$doc = new DOMDocument();
$result = $doc->loadXML($xml_string);
$error_info = null;
// 获取最后一个错误(如果有)
$last_error = libxml_get_last_error();
if ($last_error !== false) {
$error_info = $this->formatError($last_error, $source_name);
}
// 清除错误缓冲区
libxml_clear_errors();
return [
'success' => $result,
'document' => $result ? $doc : null,
'error' => $error_info
];
}
/**
* 格式化错误信息
*/
private function formatError($error, $source_name) {
$level = '';
switch ($error->level) {
case LIBXML_ERR_WARNING: $level = 'WARNING'; break;
case LIBXML_ERR_ERROR: $level = 'ERROR'; break;
case LIBXML_ERR_FATAL: $level = 'FATAL'; break;
default: $level = 'UNKNOWN'; break;
}
return [
'level' => $level,
'code' => $error->code,
'message' => trim($error->message),
'line' => $error->line,
'column' => $error->column,
'source' => $source_name,
'timestamp' => date('Y-m-d H:i:s')
];
}
/**
* 批量处理XML,只记录最后一个错误
*/
public function batchParse($xml_array) {
$results = [];
$error_count = 0;
foreach ($xml_array as $name => $xml) {
$result = $this->parseXml($xml, $name);
$results[$name] = [
'success' => $result['success'],
'error' => $result['error']
];
if (!$result['success']) {
$error_count++;
// 记录错误到日志(只记录最后一个错误)
if ($result['error']) {
$this->logError($result['error']);
}
}
}
return [
'results' => $results,
'total' => count($xml_array),
'success' => count($xml_array) - $error_count,
'errors' => $error_count
];
}
/**
* 记录错误到日志
*/
private function logError($error_info) {
$log_message = sprintf(
"[%s] [%s] XML解析错误: %s (代码: %d, 位置: 行%d) - 来源: %s\n",
$error_info['timestamp'],
$error_info['level'],
$error_info['message'],
$error_info['code'],
$error_info['line'],
$error_info['source']
);
// 写入错误日志(这里简单输出,实际应用中可以写入文件或数据库)
error_log($log_message, 3, '/tmp/xml_errors.log');
}
}
// 测试数据
$test_data = [
'正确XML' => '<?xml version="1.0"?><root><item>内容</item></root>',
'格式错误XML' => '<root><item>未闭合标签</root>',
'属性错误XML' => '<root><item id=123>属性值缺少引号</item></root>',
'空XML' => '',
'编码问题XML' => '<root><item>特殊字符 & < ></item></root>'
];
echo "<h4>XML批量处理演示:</h4>";
echo "<p>使用 libxml_get_last_error() 记录最后一个错误</p>";
$parser = new SimpleXmlParser();
$batch_result = $parser->batchParse($test_data);
// 显示结果
echo "<table class='table table-bordered table-hover'>";
echo "<thead class='table-dark'>";
echo "<tr><th>XML名称</th><th>状态</th><th>错误级别</th><th>错误消息</th><th>位置</th></tr>";
echo "</thead><tbody>";
foreach ($batch_result['results'] as $name => $result) {
if ($result['success']) {
echo "<tr class='table-success'>";
echo "<td>$name</td>";
echo "<td><span class='badge bg-success'>成功</span></td>";
echo "<td>-</td>";
echo "<td>-</td>";
echo "<td>-</td>";
echo "</tr>";
} else {
$error = $result['error'];
$row_class = '';
if ($error['level'] === 'FATAL') {
$row_class = 'table-danger';
} elseif ($error['level'] === 'ERROR') {
$row_class = 'table-warning';
}
echo "<tr class='$row_class'>";
echo "<td>$name</td>";
echo "<td><span class='badge bg-danger'>失败</span></td>";
echo "<td><span class='badge " . ($error['level'] === 'FATAL' ? 'bg-danger' : ($error['level'] === 'ERROR' ? 'bg-warning' : 'bg-info')) . "'>{$error['level']}</span></td>";
// 截断过长的错误消息
$message = htmlspecialchars($error['message']);
if (strlen($message) > 60) {
$message = substr($message, 0, 60) . '...';
}
echo "<td>$message</td>";
echo "<td>行: {$error['line']}</td>";
echo "</tr>";
}
}
echo "</tbody></table>";
// 显示统计信息
echo "<div class='alert alert-info'>";
echo "<strong>处理统计:</strong> ";
echo "总数: {$batch_result['total']}, ";
echo "成功: {$batch_result['success']}, ";
echo "失败: {$batch_result['errors']}";
echo "</div>";
// 显示日志示例
echo "<h5>错误日志示例(最后一条):</h5>";
echo "<div class='alert alert-light' style='font-family: monospace;'>";
echo "[" . date('Y-m-d H:i:s') . "] [ERROR] XML解析错误: Opening and ending tag mismatch: item line 1 and root (代码: 76, 位置: 行1) - 来源: 格式错误XML";
echo "</div>";
// 使用建议
echo "<div class='alert alert-success mt-3'>";
echo "<strong>使用 libxml_get_last_error() 的优势:</strong>";
echo "<ul class='mb-0'>";
echo "<li>性能更好,只处理一个错误对象</li>";
echo "<li>代码更简洁,适合简单错误检查</li>";
echo "<li>内存占用更少,不存储所有错误</li>";
echo "<li>适合日志记录,只记录最后/最重要的错误</li>";
echo "</ul>";
echo "</div>";
?>
下面的示例演示在解析HTML时如何使用 libxml_get_last_error() 处理错误。
<?php
/**
* HTML解析器,使用最后错误进行快速诊断
*/
class HtmlParser {
/**
* 解析HTML并返回诊断信息
*/
public function parseAndDiagnose($html, $options = []) {
// 启用内部错误处理
libxml_use_internal_errors(true);
libxml_clear_errors();
$default_options = [
'encoding' => 'UTF-8',
'recover' => true,
'options' => LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
];
$options = array_merge($default_options, $options);
$doc = new DOMDocument('1.0', $options['encoding']);
if ($options['recover']) {
$doc->recover = true;
}
// 加载HTML
$load_result = @$doc->loadHTML($html, $options['options']);
// 获取最后一个错误
$last_error = libxml_get_last_error();
// 诊断信息
$diagnosis = [
'parse_success' => $load_result,
'has_error' => ($last_error !== false),
'last_error' => $last_error,
'document_size' => $load_result ? strlen($doc->saveHTML()) : 0,
'element_count' => $load_result ? $doc->getElementsByTagName('*')->length : 0
];
// 清除错误缓冲区
libxml_clear_errors();
return [
'document' => $load_result ? $doc : null,
'diagnosis' => $diagnosis
];
}
/**
* 根据错误提供修复建议
*/
public function getFixSuggestions($error) {
if ($error === false) {
return '没有发现错误';
}
$message = trim($error->message);
$suggestions = [];
// 常见HTML错误和建议
$common_issues = [
'Tag' => '检查标签是否正确闭合',
'attribute' => '检查属性是否正确格式(属性值应该用引号括起来)',
'Entity' => 'HTML实体可能需要转义,如 & 代表 &',
'parser error' => 'HTML可能有严重的语法错误',
'expected' => '缺少预期的标签或属性',
'mismatch' => '开始和结束标签不匹配'
];
foreach ($common_issues as $keyword => $suggestion) {
if (stripos($message, $keyword) !== false) {
$suggestions[] = $suggestion;
}
}
// 如果没有匹配的建议,提供通用建议
if (empty($suggestions)) {
$suggestions[] = '检查HTML语法是否正确';
$suggestions[] = '验证HTML是否符合规范';
}
return array_unique($suggestions);
}
}
// 测试HTML(包含错误)
$test_html = '<!DOCTYPE html>
<html>
<head>
<title>测试页面</title>
</head>
<body>
<h1>HTML测试</h1>
<div class=container> <!-- 错误:属性值缺少引号 -->
<p>段落文本
<img src="image.jpg"> <!-- 错误:img标签没有alt属性 -->
</div>
<ul>
<li>项目1
<li>项目2</li>
</ul>
<script>
// JavaScript代码
console.log("Hello");
</script>
</body>
</html>';
echo "<h4>HTML解析错误诊断:</h4>";
$parser = new HtmlParser();
$result = $parser->parseAndDiagnose($test_html);
// 显示诊断信息
echo "<table class='table table-bordered' style='width: auto;'>";
echo "<thead><tr><th>诊断项</th><th>结果</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>解析是否成功</td><td>" . ($result['diagnosis']['parse_success'] ? '是' : '否') . "</td></tr>";
echo "<tr><td>是否有错误</td><td>" . ($result['diagnosis']['has_error'] ? '是' : '否') . "</td></tr>";
echo "<tr><td>文档大小</td><td>" . $result['diagnosis']['document_size'] . " 字节</td></tr>";
echo "<tr><td>元素数量</td><td>" . $result['diagnosis']['element_count'] . " 个</td></tr>";
echo "</tbody></table>";
// 显示最后一个错误(如果有)
if ($result['diagnosis']['has_error']) {
$last_error = $result['diagnosis']['last_error'];
echo "<h5>最后一个HTML解析错误:</h5>";
echo "<div class='card border-warning'>";
echo "<div class='card-header bg-warning'>";
$level = '';
switch ($last_error->level) {
case LIBXML_ERR_WARNING: $level = '警告'; break;
case LIBXML_ERR_ERROR: $level = '错误'; break;
case LIBXML_ERR_FATAL: $level = '致命错误'; break;
}
echo "HTML解析错误 - $level (代码: {$last_error->code})";
echo "</div>";
echo "<div class='card-body'>";
echo "<p><strong>错误消息:</strong> " . htmlspecialchars(trim($last_error->message)) . "</p>";
echo "<p><strong>位置:</strong> 行 {$last_error->line}, 列 " . ($last_error->column ?: '未知') . "</p>";
// 提供修复建议
$suggestions = $parser->getFixSuggestions($last_error);
if (!empty($suggestions)) {
echo "<p><strong>修复建议:</strong></p>";
echo "<ul>";
foreach ($suggestions as $suggestion) {
echo "<li>$suggestion</li>";
}
echo "</ul>";
}
echo "</div></div>";
}
// 显示解析后的HTML(如果成功)
if ($result['diagnosis']['parse_success'] && $result['document']) {
echo "<h5>解析后的HTML(已修复):</h5>";
echo "<div style='max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px; background: #f8f9fa; font-size: 0.9em;'>";
$result['document']->formatOutput = true;
$html = $result['document']->saveHTML();
// 高亮显示修改的部分(简单示例)
$html = str_replace('class=container', '<span style="background-color: #ffeb3b;">class="container"</span>', $html);
$html = str_replace('<img src="image.jpg">', '<span style="background-color: #ffeb3b;"><img src="image.jpg" alt=""></span>', $html);
echo "<pre>" . htmlspecialchars($html) . "</pre>";
echo "</div>";
echo "<p class='text-muted'><small>注意:黄色高亮显示的是解析器自动修复的部分</small></p>";
}
// HTML解析特点说明
echo "<div class='alert alert-info mt-3'>";
echo "<strong>HTML解析的特点:</strong>";
echo "<ul class='mb-0'>";
echo "<li>HTML解析器比XML解析器更宽容</li>";
echo "<li>许多HTML错误会被自动修复</li>";
echo "<li>libxml_get_last_error() 通常返回最严重的错误</li>";
echo "<li>即使有错误,HTML文档通常也能被解析</li>";
echo "</ul>";
echo "</div>";
?>
下面的示例演示在大规模XML处理场景中,如何使用 libxml_get_last_error() 进行性能优化。
<?php
/**
* 高性能XML处理器,使用最后错误进行优化
*/
class HighPerformanceXmlProcessor {
private $stats = [
'processed' => 0,
'success' => 0,
'errors' => 0,
'fatal_errors' => 0,
'last_error_time' => null,
'error_codes' => []
];
/**
* 处理大量XML数据(性能优化版)
*/
public function processBatchOptimized($xml_items, $options = []) {
$default_options = [
'chunk_size' => 100,
'log_errors' => true,
'stop_on_fatal' => false,
'memory_check' => true
];
$options = array_merge($default_options, $options);
// 启用内部错误处理
libxml_use_internal_errors(true);
$results = [];
$chunk_counter = 0;
foreach ($xml_items as $item_id => $xml_data) {
// 定期清理错误缓冲区(优化内存)
if ($chunk_counter % $options['chunk_size'] === 0) {
libxml_clear_errors();
if ($options['memory_check']) {
$this->checkMemoryUsage($chunk_counter);
}
}
// 处理单个XML
$result = $this->processSingleOptimized($xml_data, $item_id, $options);
$results[$item_id] = $result;
$this->stats['processed']++;
if ($result['success']) {
$this->stats['success']++;
} else {
$this->stats['errors']++;
if ($result['is_fatal']) {
$this->stats['fatal_errors']++;
// 如果遇到致命错误且设置了停止,则中断处理
if ($options['stop_on_fatal']) {
$this->stats['last_error_time'] = date('Y-m-d H:i:s');
break;
}
}
// 记录错误代码统计
if ($result['error_code']) {
$code = $result['error_code'];
if (!isset($this->stats['error_codes'][$code])) {
$this->stats['error_codes'][$code] = 0;
}
$this->stats['error_codes'][$code]++;
}
// 记录错误日志
if ($options['log_errors']) {
$this->logOptimizedError($result, $item_id);
}
}
$chunk_counter++;
}
// 最后清理一次
libxml_clear_errors();
return [
'results' => $results,
'stats' => $this->stats
];
}
/**
* 处理单个XML(优化版)
*/
private function processSingleOptimized($xml_data, $item_id, $options) {
$result = [
'success' => false,
'is_fatal' => false,
'error_code' => null,
'error_message' => null,
'processing_time' => 0,
'memory_used' => 0
];
$start_time = microtime(true);
$start_memory = memory_get_usage();
try {
$doc = new DOMDocument();
// 禁用外部实体(安全+性能)
$old_entity_loader = libxml_disable_entity_loader(true);
// 快速解析(不进行额外验证)
$parse_result = @$doc->loadXML($xml_data, LIBXML_NOERROR | LIBXML_NOWARNING);
// 恢复实体加载器
libxml_disable_entity_loader($old_entity_loader);
if ($parse_result) {
$result['success'] = true;
$result['data'] = $doc;
} else {
// 只获取最后一个错误(性能优化)
$last_error = libxml_get_last_error();
if ($last_error !== false) {
$result['error_code'] = $last_error->code;
$result['error_message'] = trim($last_error->message);
$result['is_fatal'] = ($last_error->level === LIBXML_ERR_FATAL);
}
}
} catch (Exception $e) {
$result['error_message'] = '异常: ' . $e->getMessage();
$result['is_fatal'] = true;
}
$end_time = microtime(true);
$end_memory = memory_get_usage();
$result['processing_time'] = round(($end_time - $start_time) * 1000, 3); // 毫秒
$result['memory_used'] = $end_memory - $start_memory; // 字节
return $result;
}
/**
* 检查内存使用
*/
private function checkMemoryUsage($chunk_counter) {
$memory = memory_get_usage(true);
$memory_mb = round($memory / 1024 / 1024, 2);
// 如果内存使用过高,强制清理
if ($memory_mb > 100) { // 超过100MB
libxml_clear_errors();
gc_collect_cycles(); // 强制垃圾回收
error_log("内存警告: 块 $chunk_counter 使用了 {$memory_mb}MB");
}
}
/**
* 记录优化后的错误日志
*/
private function logOptimizedError($result, $item_id) {
$log_entry = sprintf(
"[%s] [%s] XML处理错误: %s (代码: %s, 耗时: %.3fms)\n",
date('Y-m-d H:i:s'),
$result['is_fatal'] ? 'FATAL' : 'ERROR',
$result['error_message'] ? substr($result['error_message'], 0, 100) : '未知错误',
$result['error_code'] ?: 'N/A',
$result['processing_time']
);
// 简化的日志记录(实际应用中可写入文件)
error_log($log_entry, 3, '/tmp/xml_perf_errors.log');
}
/**
* 获取统计信息
*/
public function getStats() {
return $this->stats;
}
}
// 生成大量测试数据
echo "<h4>高性能XML批处理演示:</h4>";
echo "<p>模拟处理大量XML数据,使用 libxml_get_last_error() 优化性能</p>";
// 创建测试数据(1000个XML,其中10%有错误)
$test_items = [];
for ($i = 0; $i < 1000; $i++) {
if ($i % 10 === 0) {
// 每10个中有一个格式错误的XML
$test_items["item_$i"] = '<root><item>未闭合标签</root>';
} else {
$test_items["item_$i"] = "<?xml version=\"1.0\"?><root><item id=\"$i\">数据内容 $i</item></root>";
}
}
echo "<p>生成测试数据: " . count($test_items) . " 个XML文档</p>";
// 启动处理器
$processor = new HighPerformanceXmlProcessor();
// 处理数据(性能优化模式)
$start_time = microtime(true);
$result = $processor->processBatchOptimized($test_items, [
'chunk_size' => 50,
'log_errors' => true,
'stop_on_fatal' => false
]);
$end_time = microtime(true);
$stats = $result['stats'];
echo "<h5>处理结果统计:</h5>";
echo "<table class='table table-bordered' style='width: auto;'>";
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><span class='badge bg-dark'>{$stats['fatal_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_items), 3) . " 毫秒</td></tr>";
echo "</tbody></table>";
// 显示错误代码统计
if (!empty($stats['error_codes'])) {
echo "<h5>错误代码统计:</h5>";
echo "<table class='table table-sm table-bordered' style='width: auto;'>";
echo "<thead><tr><th>错误代码</th><th>出现次数</th></tr></thead>";
echo "<tbody>";
arsort($stats['error_codes']);
foreach ($stats['error_codes'] as $code => $count) {
echo "<tr><td><code>$code</code></td><td>$count</td></tr>";
}
echo "</tbody></table>";
}
// 性能优化说明
echo "<div class='alert alert-success mt-3'>";
echo "<strong>使用 libxml_get_last_error() 的性能优化策略:</strong>";
echo "<ul class='mb-0'>";
echo "<li><strong>减少内存占用</strong>:只获取最后一个错误,不存储所有错误数组</li>";
echo "<li><strong>减少CPU开销</strong>:避免遍历和格式化大量错误对象</li>";
echo "<li><strong>定期清理</strong>:按块大小清理错误缓冲区,防止内存泄漏</li>";
echo "<li><strong>简化日志</strong>:只记录关键错误信息,减少I/O操作</li>";
echo "<li><strong>快速失败</strong>:遇到致命错误时快速中断,减少无效处理</li>";
echo "</ul>";
echo "</div>";
// 对比性能数据
echo "<h5>性能对比:</h5>";
echo "<table class='table table-bordered table-sm' style='width: auto;'>";
echo "<thead><tr><th>方法</th><th>内存占用</th><th>处理时间</th><th>适用场景</th></tr></thead>";
echo "<tbody>";
echo "<tr><td>libxml_get_errors()</td><td>较高</td><td>较慢</td><td>需要所有错误细节的调试场景</td></tr>";
echo "<tr><td>libxml_get_last_error()</td><td>较低</td><td>较快</td><td>批量处理、日志记录、生产环境</td></tr>";
echo "</tbody></table>";
?>
libxml_use_internal_errors(true),否则函数返回 FALSE。libxml_clear_errors() 清理。libxml_get_errors(),只需要快速检查时使用 libxml_get_last_error()。libxml_get_last_error() 性能更好,内存占用更少。libxml_clear_errors() 防止错误累积。