Composer require报“Package not found”时,应根据项目类型选择phpoffice/phpspreadsheet(纯PHP)或maatwebsite/excel(Laravel),注意PHP版本(≥7.4)、依赖关系、缓存配置及Excel二进制格式特性。

composer require 时提示 “Package not found”
不是所有叫 Excel 的包都能直接用,phpoffice/phpspreadsheet 是当前唯一被广泛维护的主流选择。老项目里常见的 maatwebsite/excel(Laravel Excel)本质是它上层封装,但必须匹配 Laravel 版本;单独用 Composer 装这个包却没装 Laravel,就会报错找不到依赖。
- 纯 PHP 项目,直接运行
composer require phpoffice/phpspreadsheet - Laravel 项目,优先选
composer require maatwebsite/excel,它会自动拉取phpoffice/phpspreadsheet并绑定服务提供者 - 如果手动装了
maatwebsite/excel却没生效,检查是否漏执行php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" - PHP 版本低于 7.4 会安装失败——
phpoffice/phpspreadsheetv2.x 要求 PHP ≥ 7.4,v1.x 已停止更新且不兼容 PHP 8.1+
读 Excel 文件时中文乱码或空行异常
根本原因不是编码问题,而是 PhpSpreadsheet 默认按 Excel 内部结构解析,不自动处理 BOM、空工作表、隐藏列/行、合并单元格残留值。尤其从 Windows Excel 导出的 .xlsx,常带不可见格式干扰。
- 加载前加判断:
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::load($filePath);后立刻调用$reader->getSheetCount(),为 0 就说明文件损坏或为空 - 读取单个 sheet 时,别用
getHighestRow()当真实数据行数——它包含空行。改用getHighestDataRow(1)(参数 1 是列号 A)获取该列最后一个非空行 - 中文字段显示成 或乱码?不是 UTF-8 问题,是单元格样式里设置了“字体未嵌入”,用
$cell->getValue()前先试$cell->getFormattedValue(),后者会走 Excel 内置格式化逻辑 - 避免用
toArray()一键转数组——它会把合并单元格重复填充,导致数据错位。应遍历$worksheet->getRowIterator()手动提取
导出大文件内存爆掉或超时
PhpSpreadsheet 默认把整张表载入内存,10 万行 × 50 列就轻松吃掉 500MB+。不是代码写错了,是默认模式根本不适合大批量导出。
- 导出前必须设内存缓存:
\PhpOffice\PhpSpreadsheet\Settings::setCacheStorageMethod(\PhpOffice\PhpSpreadsheet\Settings::CACHE_TO_PHPTEMP); - 写入时禁用公式预计算:
$spreadsheet->getActiveSheet()->setCellValueExplicit('A1', '文本', \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);,避免触发公式引擎 - 真要导 >10 万行,放弃
PhpSpreadsheet,改用box/spout(只支持 .xlsx/.csv,无样式,但内存恒定在 3–5MB):composer require box/spout - Web 环境导出务必加
set_time_limit(0)和ini_set('memory_limit', '-1'),但更稳妥的是扔进队列异步生成,返回下载链接
maatwebsite/excel 导出模板渲染失败
很多人以为 Blade 模板里写 @foreach($data as $row) {{ $row->name }} @endforeach 就能自动塞进 Excel,其实 Maatwebsite\Excel 的 FromView 只支持简单 HTML 表格标签,不支持 Blade 指令嵌套、组件、slot,也不解析 PHP 代码。
- 模板中只能用
<table><tr><td>xxx</td></tr></table>结构,<div>、<section>会被忽略 - 样式仅支持内联
,CSS 类名无效;colspan/rowspan可用,但合并逻辑由 Excel 渲染器推断,容易错位 - 动态标题栏?别在 Blade 里 if/else,改用
WithHeadings接口配合headings()方法返回数组 - 想复用现有 Blade 表格?先用
view('xxx')->render()输出 HTML 字符串,再用SimpleHtmlDom或正则剔除非 table 内容,否则导入 Excel 时会报Invalid character
maatwebsite/excel 和 phpoffice/phpspreadsheet 的职责边界,二是把 Excel 当成纯数据容器,忽略了它本质是个带样式的二进制格式——哪怕只是读一列数字,也得过一遍样式解析和公式上下文。










