Много было написано об использовании памяти PHPExcel на форуме PHPExcel; так что чтение некоторых из этих предыдущих обсуждений может дать вам несколько идей. PHPExcel хранит представление электронной таблицы в памяти и подвержено ограничениям памяти PHP.
Физический размер файла в значительной степени не имеет значения ... гораздо важнее знать, сколько ячеек (строк * столбцов на каждом листе) он содержит.
«Эмпирическое правило», которое я всегда использовал, составляет в среднем около 1 КБ / ячейка, поэтому для книги на 5 МБ требуется 5 ГБ памяти. Тем не менее, существует ряд способов уменьшить это требование. Их можно комбинировать, в зависимости от того, какая именно информация вам нужна в вашей рабочей книге, и что вы хотите с ней делать.
Если у вас есть несколько рабочих листов, но вам не нужно загружать их все, вы можете ограничить рабочие листы, которые Reader будет загружать, используя метод setLoadSheetsOnly ().
Чтобы загрузить один именованный рабочий лист:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #2';
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$objReader->setLoadSheetsOnly($sheetname);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Или вы можете указать несколько листов одним вызовом setLoadSheetsOnly (), передав массив имен:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetnames = array('Data Sheet #1','Data Sheet #3');
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$objReader->setLoadSheetsOnly($sheetnames);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Если вам нужен только доступ к части листа, вы можете определить фильтр чтения, чтобы определить, какие ячейки вы действительно хотите загрузить:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #3';
/** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read rows 1 to 7 and columns A to E only
if ($row >= 1 && $row <= 7) {
if (in_array($column,range('A','E'))) {
return true;
}
}
return false;
}
}
/** Create an Instance of our Read Filter **/
$filterSubset = new MyReadFilter();
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load
It's more efficient to limit sheet loading in this manner rather than coding it into a Read Filter **/
$objReader->setLoadSheetsOnly($sheetname);
echo 'Loading Sheet using filter';
/** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
$objReader->setReadFilter($filterSubset);
/** Load only the rows and columns that match our filter from $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Используя фильтры чтения, вы также можете читать рабочую книгу в виде «чанков», так что только один чанк может быть резидентным в любой момент времени:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example2.xls';
/** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */
class chunkReadFilter implements PHPExcel_Reader_IReadFilter {
private $_startRow = 0;
private $_endRow = 0;
/** Set the list of rows that we want to read */
public function setRows($startRow, $chunkSize) {
$this->_startRow = $startRow;
$this->_endRow = $startRow + $chunkSize;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
return true;
}
return false;
}
}
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 20;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new chunkReadFilter();
/** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
$objReader->setReadFilter($chunkFilter);
/** Loop to read our worksheet in "chunk size" blocks **/
/** $startRow is set to 2 initially because we always read the headings in row #1 **/
for ($startRow = 2; $startRow <= 65536; $startRow += $chunkSize) {
/** Tell the Read Filter, the limits on which rows we want to read this iteration **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Load only the rows that match our filter from $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
// Do some processing here
// Free up some of the memory
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
}
Если вам не нужно загружать информацию о форматировании, а только данные рабочего листа, то метод setReadDataOnly () сообщит читателю только о загрузке значений ячеек, игнорируя любое форматирование ячеек:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader that we only want to load cell data, not formatting **/
$objReader->setReadDataOnly(true);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Использовать кэширование ячеек. Это метод сокращения памяти PHP, которая требуется для каждой ячейки, но за счет скорости. Он работает, храня объекты ячеек в сжатом формате или вне памяти PHP (например, диск, APC, memcache) ... но чем больше памяти вы экономите, тем медленнее будут выполняться ваши скрипты. Однако вы можете уменьшить объем памяти, необходимый каждой ячейке, примерно до 300 байт, поэтому для гипотетических ячеек 5M потребуется около 1,4 ГБ памяти PHP.
Кэширование ячеек описано в разделе 4.2.1 документации разработчика
EDIT
Глядя на свой код, вы используете итераторы, которые не особенно эффективны, и создаете массив данных ячейки. Возможно, вы захотите взглянуть на метод toArray (), который уже встроен в PHPExcel и делает это для вас. Также взгляните на это недавнее обсуждение на SO о новом варианте метода rangeToArray () для построения ассоциативного массива данных строки.