如何在PhpSpreadsheet工作簿中按名称排序工作表且不打乱索引?
问题场景
使用PhpSpreadsheet 1.18(PHP 8.1 + Laravel 8.75)生成.xlsx评估报告,已实现将不同类别评估(如Evaluation A、Evaluation B)合并到"MasterSpreadsheet"单个工作簿的功能,但需要按工作表名称对最终工作簿内的工作表进行排序。当前尝试克隆原工作簿并按字母顺序插入工作表的方法报错:Undefined array key 2,代码如下:
foreach ($sheetNames as $name) { $sheet = $spreadsheet->getSheetByName($name); if (!$sheet) { error_log("Sheet $name doesn't exist in this workbook."); continue; } $clonedSheet = clone $sheet; $clonedSheet->setTitle($name); $newSpreadsheet->addSheet($clonedSheet); }
错误原因
直接克隆工作表对象时,工作表内部的$_parent(原工作簿引用)和$_index(原索引)属性未被重置,添加到新工作簿时会触发索引冲突,导致数组键不存在的错误。
解决方案
方案1:直接在原工作簿中调整工作表顺序(推荐)
无需创建新工作簿,直接对原工作簿的工作表进行排序调整:
// 获取所有工作表名称并按字母顺序排序 $sheetNames = $spreadsheet->getSheetNames(); natsort($sheetNames); // 遍历排序后的名称,将工作表移动到对应索引位置 foreach ($sheetNames as $targetIndex => $sheetName) { $sheet = $spreadsheet->getSheetByName($sheetName); if (!$sheet) { error_log("Sheet $sheetName doesn't exist in this workbook."); continue; } // 先激活目标工作表,再移动到指定索引 $currentIndex = $spreadsheet->getIndex($sheet); if ($currentIndex !== $targetIndex) { $spreadsheet->setActiveSheetIndex($currentIndex); $spreadsheet->moveSheet($targetIndex); } }
方案2:创建新工作簿并复制内容(避免克隆冲突)
如果必须使用新工作簿,通过创建新工作表并复制原表内容的方式替代克隆:
$newSpreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); // 删除新工作簿默认创建的空白工作表 $newSpreadsheet->removeSheetByIndex(0); $sheetNames = $spreadsheet->getSheetNames(); natsort($sheetNames); foreach ($sheetNames as $sheetName) { $originalSheet = $spreadsheet->getSheetByName($sheetName); if (!$originalSheet) { error_log("Sheet $sheetName doesn't exist in this workbook."); continue; } // 创建新工作表并设置标题 $newSheet = $newSpreadsheet->createSheet(); $newSheet->setTitle($sheetName); // 复制原工作表的单元格数据 $newSheet->fromArray($originalSheet->toArray(), null, 'A1'); // (可选)复制单元格样式 foreach ($originalSheet->getRowIterator() as $row) { $cellIterator = $row->getCellIterator(); $cellIterator->setIterateOnlyExistingCells(false); foreach ($cellIterator as $cell) { $coord = $cell->getCoordinate(); $newSheet->getStyle($coord)->applyFromArray( $originalSheet->getStyle($coord)->getArrayCopy() ); } } }
内容的提问来源于stack exchange,提问作者Gou
相关产品推荐
相关产品推荐

