Как стать автором
Обновить

FastExcelWriter — избавление от проклятия PhpSpreadsheet

Уровень сложностиСредний
Время на прочтение3 мин
Количество просмотров2.6K

Наверняка каждый php-разработчик, хоть раз сталкивавшийся с чтением или записью Excel-файлов, знает про библиотеку PhpSpreadsheet (в прошлом - PHPExcel). Это мощная библиотека на чистом php, которая позволяет читать, а, главное, создавать Excel-таблицы. И все с ней хорошо, пока работаешь с небольшим набором данных. Но при работе с большими файлами PhpSpreadsheet начинает чудовищно отжирать память, да и производительность резко падает, и php-скрипт, использующий библиотеку, часто просто отваливается по таймауту. И проблема - в архитектуре библиотеки.

Библиотека PhpSpreadsheet, казалось бы, спроектирована очень правильно: листы таблицы, строки, ячейки, прочие сущности - это все классы, стили, форматы и всевозможные свойства тоже состоят из классов. И когда создается таблица, то в памяти создается огромное количество связанных между собой объектов, им задаются свойства, выполняются всевозможные манипуляции, ячейки заполняются данными, всё-всё это держится в памяти, и пишется в файл только в момент сохранения.

И вот однажды, когда ресурсы на генерацию большого Excel-файла превысили все разумные значения, я начал искать альтернативу известной библиотеке. Альтернатива нашлась. В отличие от PhpSpreadsheet, тут все было упаковано в один класс, возможности по форматированию и стилям - скромнее некуда, но зато XLSX-файл создавался в разы быстрее, а потребление памяти было вообще копеечное. А все потому, что тут был реализован совсем иной принцип - данные не накапливались в памяти, а построчно сразу выводились в файл. Вдохновившись этой идеей, я и создал свою библиотеку FastExcelWriter.

Я сохранил тот же принцип - данные пишутся, практически, сразу во временный XML-файл, который потом добавляется в итоговый XLSX-файл (на всякий случай напомню, что XLSX - это ZIP-архив с XML-файлами), активно использую массивы вместо объектов (что тоже дает прирост скорости). Разумеется, я использую классы, но без фанатизма, по минимуму.

На сегодняшний день библиотека FastExcelWriter - одна из самых быстрых (и экономных по потреблению памяти) для создания XLSX-файлов на php, скорость генерации файлов с ее помощью у меня получалась в 7-9 раз выше, чем с PhpSpreadsheet.

При этом она поддерживает почти все возможности, включая стили оформления, условное форматирование, вставку изображений, диаграмм, примечаний, валидацию данных. Кроме того, интерфейс взаимодействия с библиотекой получился гораздо более лаконичным. Ниже приведены для сравнения два фрагмента добавления условного форматирования

Скрытый текст

Код с использованием PhpSpreadsheet

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$spreadsheet = new Spreadsheet();
$conditional = new Conditional();
$conditional->setConditionType(Conditional::CONDITION_CELLIS);
$conditional->setOperatorType(Conditional::OPERATOR_GREATERTHAN);
$conditional->addCondition(80);
$conditional->getStyle()->getFont()->getColor()->setARGB(Color::COLOR_DARKGREEN);
$conditional->getStyle()->getFill()->setFillType(Fill::FILL_SOLID);
$conditional->getStyle()->getFill()->getStartColor()->setARGB(Color::COLOR_GREEN);

$conditionalStyles = $spreadsheet->getActiveSheet()->getStyle('A1:A10')->getConditionalStyles();
$conditionalStyles[] = $conditional;

$spreadsheet->getActiveSheet()->getStyle('A1:A10')->setConditionalStyles($conditionalStyles);

$writer = new Xlsx($spreadsheet);
$writer->save('demo.xlsx');

Код с использованием FastExcelWriter

use avadim\FastExcelWriter\Conditional\Conditional;
use avadim\FastExcelWriter\Excel;

$excel = Excel::create();
$style = Excel::newStyle()->setFontColor('#008000')->setFillColor('#00ff00');
$conditional = Conditional::greaterThan(80, $style->toArray());
$excel->sheet()->addConditionalFormatting('A1:A10', [$conditional]);

$excel->save('demo.xlsx');

Конечно, с помощью библиотеки можно записывать в ячейки и формулы, но есть нюанс: значения формул не высчитываются и не записываются в файл. Но когда созданный файл открывается потом в соответствующей программе (MS Excel, Libre Office и пр.), то эти программы все рассчитают и отобразят значения налету.

А что насчет чтения XLSX-файлов? - спросите вы. А для этого есть аналогичная библиотека - FastExcelReader, и она тоже в разы быстрее читает файлы, чем та же PhpSpreadsheet.

А еще есть FastExcelLaravel - обертка, которая включает в себя сразу обе библиотеки (FastExcelWriter и FastExcelReader) и содержит дополнительные методы для импорта и экспорта моделей Laravel.

И все это — оупенсорс. Берите, пользуйтесь, наслаждайтесь!

Теги:
Хабы:
+22
Комментарии3

Публикации

Работа

PHP программист
79 вакансий

Ближайшие события