导出大数据应避免db::select()和fromarray(),改用setcellvaluebycolumnandrow()分块写入+gc_collect_cycles();日期用setvalueexplicit()+格式码;设simsun全局字体、正确响应头、bom及ob_end_clean();超10万行优先用游标+流式csv。

别用 Db::select() 查全量再喂给 PhpSpreadsheet,5000 行以上基本就爆内存;真要导 Excel,必须手动控制单元格写入节奏,或直接降级用 CSV。
为什么 fromArray() 是大数据导出的雷区
它会把整个二维数组转成 PHP 对象塞进内存,再由 PhpSpreadsheet 构建所有单元格对象——查 1w 行 + fromArray(),PHP 内存轻松破 300MB。更糟的是,fromArray() 会丢掉原始数据类型(比如 datetime 字段变成字符串),Excel 里日期无法排序、筛选。
- 查 5w 行用户数据 →
Db::name('user')->select()已占约 120MB 内存 -
$sheet->fromArray($data)→ 再吃 200MB+,触发Fatal error: Allowed memory size exhausted - 正确替代:用
setCellValueByColumnAndRow()循环写,每写 1000 行调一次gc_collect_cycles() - 日期字段别用
$row['created_at']->format('Y-m-d'),改用setValueExplicit($timestamp, DataType::TYPE_NUMERIC)+ 格式码
中文乱码和 Excel 打开报 #VALUE! 的真实原因
不是编码没设对,是字体和响应头没配齐。Excel 桌面端默认不识别 UTF-8 字体,纯靠 HTTP 响应头和内部样式双重指定才生效。
- 必须设全局字体:
$spreadsheet->getDefaultStyle()->getFont()->setName('SimSun')(不能只设单元格) - 响应头缺一不可:
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8 - 中文文件名必须
rawurlencode(),否则 Safari/Edge 下载失败 - 表头字段含中文?先用
iconv('UTF-8', 'GB2312//IGNORE', $str)转一下再写入,比硬扛更稳
游标查询 + 流式 CSV 是最靠谱的兜底方案
当运营提需求说“导出全部订单”,别硬刚 Excel,先看量级。10w 行 CSV 生成只要 0.8 秒、内存峰值不到 4MB;同等数据导 Excel,没做分块几乎必挂。
- 用
Db::name('order')->cursor()替代select(),逐行取,不攒数组 -
fputcsv()自动处理逗号、换行、引号,不用自己str_replace() - 中文字段前必须输出 BOM:
echo "\xEF\xBB\xBF",否则 Windows Excel 默认 ANSI 解码 - 务必在
header()前执行ob_end_clean(),否则 HTML 空白符混进 CSV 开头,Excel 打开第一列全乱码
真正卡住人的从来不是“怎么写入单元格”,而是游标没关、BOM 忘加、内存限制硬调、字体名拼错——这些点漏一个,导出就静默失败或打开是方块。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











