
本文详解使用 phpspreadsheet 库遍历指定目录下所有 `.xlsx` 文件,逐行提取 a 列(name)和 b 列(price),统一合并到一个扁平化二维数组中,避免重复索引与数据覆盖问题。
在 PHP 中批量处理 Excel 文件时,常见误区是将每个文件的数据存入独立子数组(如 $myarr[] = $array),导致最终结果为嵌套三维结构([ [row1, row2], [row1, row2], ... ]),不仅增加后续处理复杂度,更易因循环内变量复用引发数据错位或重复计数——正如提问中出现的“500–600 条实际数据却输出 1200 条”问题,根源正是 $array 在每次外层循环中未重置,且内层 for 循环持续向同一 $array 写入,而 $myarr[] = $array 又将其整体追加,造成指数级冗余。
正确做法是跳过中间临时数组,直接将每行解析结果追加至顶层 $myarr,确保最终得到的是扁平、有序、无嵌套的一维数组,每项均为 ['name' => ..., 'price' => ...] 结构。以下是优化后的完整实现:
setReadDataOnly(true); // 仅读取值,忽略样式/公式
$spreadsheet = $reader->load($file);
$worksheet = $spreadsheet->getSheet(0); // 默认读取第一个工作表
$highestRow = $worksheet->getHighestRow();
// 从第2行开始读取(假设第1行为标题)
for ($row = 2; $row <= $highestRow; $row++) {
$name = $worksheet->getCell('A' . $row)->getValue() ?: '';
$price = $worksheet->getCell('B' . $row)->getValue() ?: '';
$myarr[] = [
'name' => (string) $name,
'price' => is_numeric($price) ? (float) $price : 0.0
];
}
// 可选:释放内存(对大文件尤其重要)
$spreadsheet->disconnectWorksheets();
unset($spreadsheet, $worksheet, $reader);
} catch (Exception $e) {
error_log("Failed to process {$file}: " . $e->getMessage());
continue;
}
}
// 输出结果(生产环境建议用 JSON 或数据库存储)
echo '';
print_r($myarr);
echo '
';
echo "总计导入 " . count($myarr) . " 条商品记录。
";
?>✅ 关键改进点说明:
- 扁平化结构:不再使用 $array[$row] 构建局部索引数组,而是 $myarr[] = [...] 直接追加,保证最终为线性列表;
- 健壮性增强:添加 try-catch 捕获单个文件读取异常,避免一个损坏文件中断全部流程;
- 内存管理:调用 disconnectWorksheets() 并 unset() 对象,防止大文件循环中内存泄漏;
- 数据类型规范:显式转换 name 为字符串、price 为浮点数,提升后续计算与导出可靠性;
- 标题行跳过:明确从第 2 行起读取,符合常规 Excel 表头设计。
⚠️ 注意事项:
- 确保 prices/ 目录存在且 PHP 有读取权限;
- 所有 .xlsx 文件需结构一致(A 列为 name,B 列为 price,无空行干扰行号);
- 若存在多工作表需求,可遍历 $spreadsheet->getSheetCount() 后逐表处理;
- 处理超千行文件时,建议结合分批读取或流式解析(如 PhpSpreadsheet 的 ChunkReadFilter)进一步优化性能。
至此,你已获得一个高效、稳定、可维护的 Excel 批量合并方案——数据准确、结构清晰、易于扩展。










