PhpSpreadsheet是PHPExcel唯一官方继任者,必须迁移;因API差异大,需注意单元格初始化、禁用自动列宽、显式设置数据类型及使用绝对路径保存文件。

PHPExcel 已停止维护,直接升级到 PhpSpreadsheet 是唯一稳妥选择;旧项目迁移时,不能简单替换类名,核心 API 差异大,尤其单元格赋值、样式设置和文件保存逻辑。
为什么 setCellValue() 会报 “Call to a member function getStyle() on null”
这是最常踩的坑:PhpSpreadsheet 不再允许对未初始化的单元格直接调用样式方法。旧代码里 $sheet->setCellValue('A1', 'xxx') 后立刻 $sheet->getStyle('A1')->applyFromArray(...) 可能失败——因为 setCellValue() 并不自动创建单元格对象(尤其是空值或 null 赋值时)。
- 务必先确保单元格已存在:用
$sheet->getCell('A1')或显式赋值非 null 值(如空字符串'')触发初始化 - 更安全的做法是统一用
$sheet->setCellValueExplicit('A1', 'value', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING),它强制创建单元格并指定类型 - 批量设样式前,先用
$sheet->getCell('A1')->setValue('xxx')替代setCellValue(),可避免隐式跳过初始化
导出大文件时内存爆掉,setAutoSize(true) 是罪魁祸首
自动列宽计算需遍历整列所有单元格内容并测量字体宽度,对万行以上数据极易触发 Fatal error: Allowed memory size exhausted。这不是 bug,是设计使然。
- 导出前禁用自动列宽:
$sheet->getDefaultColumnDimension()->setAutoSize(false) - 手动设置常用列宽,例如:
$sheet->getColumnDimension('A')->setWidth(20) - 真需要自适应?仅对关键列(如标题行)用
$sheet->calculateColumnWidth('A')单独算,别全量调用 - 配合单元格缓存策略:
\PhpOffice\PhpSpreadsheet\Settings::setCacheStorageMethod(\PhpOffice\PhpSpreadsheet\Settings::CACHE_TO_PHP_TEMP)
中文乱码、公式失效、日期变数字 —— 编码和类型没设对
PhpSpreadsheet 默认按 Excel 原生规则处理数据类型,不依赖 PHP 文件编码。乱码往往源于字符串未声明为 UTF-8 字符串类型,公式失效则因写入时被当作文本处理。
立即学习“PHP免费学习笔记(深入)”;
- 中文内容必须用
setCellValueExplicit()并指定\PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING,否则可能被误判为数值或公式 - 写入公式以
=开头,但必须用setCellValue()(不是setCellValueExplicit),且确保单元格类型为默认(不强制 STRING) - 日期要转为 Excel 序列值:
\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(strtotime('2024-01-01')),再用setCellValue()写入,最后设单元格格式为日期 - 导出前设时区:
date_default_timezone_set('Asia/Shanghai'),避免时间偏移
最易被忽略的是:save() 方法不接受相对路径,$writer->save('report.xlsx') 会尝试写入当前工作目录,而 CLI 和 Web 环境工作目录不同;务必用绝对路径,比如 __DIR__ . '/exports/report.xlsx',并确认目录有写权限。



















