首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHPExcel 合併與拆分儲存格完整指南:mergeCells、unmergeCells 實戰與樣式保留技巧

     編輯:PHP 相關知識

PHPExcel 合併與拆分儲存格完整指南:mergeCells、unmergeCells 實戰與樣式保留技巧

PHPExcel (現併入 PhpSpreadsheet) 處理合併儲存格是報表匯出常見需求。本文詳解 mergeCells、unmergeCells 用法、合併前清空值避免資料殘留、拆分後樣式還原、批量合併效能優化,並提供遷移 PhpSpreadsheet 的對照表。

一、核心 API 速查

<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\IOFactory;

$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();

// 合併儲存格區域 (左上:右下)
$sheet->mergeCells('A1:C1');        // A1:C1 合併為單一儲存格
$sheet->mergeCells('A2:B3');        // 2x2 區域合併

// 設置合併後儲存格的值 (只能寫左上角儲存格)
$sheet->setCellValue('A1', '標題橫跨三欄');
$sheet->setCellValue('A2', '2x2 區域合併');

// 取得合併區域陣列
$merges = $sheet->getMergeCells(); // ['A1:C1', 'A2:B3']

// 拆分合併 (還原為獨立儲存格)
$sheet->unmergeCells('A1:C1');
$sheet->unmergeCells('A2:B3');
// 拆分後:原合併區域所有儲存格值清空,樣式重置為預設
?>

二、實戰場景:報表標題跨欄 + 明細分組合併

<?php
function exportReport(array $data): void
{
    $spreadsheet = new Spreadsheet();
    $sheet = $spreadsheet->getActiveSheet();

    // 1. 標題列合併
    $sheet->mergeCells('A1:F1');
    $sheet->setCellValue('A1', '2024 年度銷售報表');
    $sheet->getStyle('A1')->getFont()->setBold(true)->setSize(16);
    $sheet->getStyle('A1')->getAlignment()->setHorizontal('center');

    // 2. 表頭
    $headers = ['部門', '銷售額', '訂單數', '客單價', '轉化率', '備註'];
    foreach ($headers as $i => $h) {
        $col = chr(ord('A') + $i);
        $sheet->setCellValue($col . '2', $h);
    }
    $sheet->getStyle('A2:F2')->getFont()->setBold(true);

    // 3. 明細資料 + 部門分組合併 (A欄相同部門合併)
    $row = 3;
    $deptStartRow = 3;
    $prevDept = null;

    foreach ($data as $idx => $record) {
        $col = 0;
        foreach (['dept', 'amount', 'orders', 'avg_price', 'conv_rate', 'remark'] as $field) {
            $cell = chr(ord('A') + $col++) . $row;
            $sheet->setCellValue($cell, $record[$field] ?? '');
        }

        // 部門變更時合併上一組 A欄
        if ($prevDept !== null && $record['dept'] !== $prevDept) {
            $sheet->mergeCells("A{$deptStartRow}:A" . ($row - 1));
            $sheet->getStyle("A{$deptStartRow}:A" . ($row - 1))
                  ->getAlignment()->setVertical('center');
            $deptStartRow = $row;
        }
        $prevDept = $record['dept'];
        $row++;
    }
    // 最後一組
    if ($deptStartRow < $row) {
        $sheet->mergeCells("A{$deptStartRow}:A" . ($row - 1));
        $sheet->getStyle("A{$deptStartRow}:A" . ($row - 1))
              ->getAlignment()->setVertical('center');
    }

    // 4. 自動欄寬
    foreach (range('A', 'F') as $col) {
        $sheet->getColumnDimension($col)->setAutoSize(true);
    }

    // 5. 輸出下載
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment; filename="report.xlsx"');
    $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
    $writer->save('php://output');
}

// 測試資料
$data = [
    ['dept'=>'華東', 'amount'=>100, 'orders'=>10, 'avg_price'=>10, 'conv_rate'=>'5%', 'remark'=>''],
    ['dept'=>'華東', 'amount'=>200, 'orders'=>15, 'avg_price'=>13.3, 'conv_rate'=>'6%', 'remark'=>''],
    ['dept'=>'華南', 'amount'=>150, 'orders'=>12, 'avg_price'=>12.5, 'conv_rate'=>'5.5%', 'remark'=>''],
];
exportReport($data);
?>

三、合併儲存格的 5 大坑與解法

坑點現象解法
合併前儲存格有值非左上角值被隱藏,匯出檔案打開顯示空白合併前 只保留左上角值,其餘 setCellValue('', '') 清空
拆分後值/樣式丟失unmergeCells 會清空整個區域值並重置樣式拆分前 備份值與樣式,拆分後逐一寫回
重疊合併拋出 Exception: "Cell range overlaps"邏輯層檢查 getMergeCells() 避免重疊
合併區域寫入非左上角值寫入無效,讀取時為空嚴格只操作左上角儲存格
大量合併效能極差幾千次 mergeCells 導致 XML 膨脹、寫入緩慢批量構建合併陣列,一次性 setMergeCells($arr) (PhpSpreadsheet 1.18+)

四、PhpSpreadsheet 遷移對照表 (PHPExcel 已停止維護)

PHPExcelPhpSpreadsheet備註
PHPExcel_IOFactoryPhpOffice\PhpSpreadsheet\IOFactory命名空間變更
$objPHPExcel->getActiveSheet()$spreadsheet->getActiveSheet()類名 Spreadsheet
mergeCells('A1:B2')$sheet->mergeCells('A1:B2')API 相容
setCellValue('A1', 'val')$sheet->setCellValue('A1', 'val')相容
$style->getFont()->setBold(true)$style->getFont()->setBold(true)相容
無$sheet->setMergeCells(['A1:B2','C1:D2'])新增批量設置

五、效能優化:批量合併 + 串流寫入

<?php
// PhpSpreadsheet 1.18+ 支援批量設置合併
$merges = [];
// ... 邏輯計算所有合併區域 ...
$sheet->setMergeCells($merges); // 一次性寫入 XML,避免重複 DOM 操作

// 超大報表 (>5萬行) 改用串流寫入
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->setUseDiskCaching(true); // 使用臨時檔緩存,降低記憶體
$writer->setPreCalculateFormulas(false);
$writer->save('php://output');
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved