抽象類別 ExportCSV 依總筆數與每批筆數計算批次,迴圈分批寫入,解決大量資料匯出記憶體溢出問題。
getExportTotal()、getExportFields()、getExportData($offset,$limit) 由子類別實作。setPageSize()、檔名 setExportName()、分隔符 setSeparator()、定界符 setDelimiter()。<?php
abstract class ExportCSV{
protected $total=0; $pagesize=500; $exportName='export.csv'; $separator=','; $delimiter='"';
abstract protected function getExportTotal();
abstract protected function getExportFields();
abstract protected function getExportData($offset,$limit);
public function setPageSize($pagesize){ if(is_numeric($pagesize)&&$pagesize>0) $this->pagesize=$pagesize; }
public function setExportName($filename){ if($filename) $this->exportName=$filename; }
public function setSeparator($sep){ if($sep) $this->separator=$sep; }
public function setDelimiter($del){ if($del) $this->delimiter=$del; }
public function export(){
$this->total = $this->getExportTotal(); if(!$this->total) return false;
$pagecount = ceil($this->total/$this->pagesize);
$fields = $this->getExportFields();
// 設定 HTTP 標頭輸出 CSV...
for($page=0;$page<$pagecount;$page++){
$offset = $page*$this->pagesize;
$data = $this->getExportData($offset,$this->pagesize);
// 格式化並輸出每列
}
}
private function formatCSV($row){ /* 逸出雙引號、包裹定界符 */ }
private function escape($str){ return str_replace('"','""',$str); }
}
?>
class UserExport extends ExportCSV{
protected function getExportTotal(){ return User::count(); }
protected function getExportFields(){ return array('ID','姓名','Email','建立時間'); }
protected function getExportData($offset,$limit){
return User::find()->limit($limit)->offset($offset)->asArray()->all();
}
}
$exporter = new UserExport();
$exporter->setPageSize(1000);
$exporter->export();