MNB PHPExcel vs PhpSpreadsheet Performance Benchmark
Compare MNB PHPExcel and PhpSpreadsheet with a reproducible PHP benchmark for elapsed time, peak memory, rows processed and package fit.
Updated
MnbExcel::read()ReadSession::rows()ReadSession::withHeaderRow()ReadSession::withOptions()What you will learn
- Build a repeatable large-XLSX benchmark without inventing performance claims.
- Compare equivalent value-only workloads in separate PHP processes.
- Publish the file, versions, extensions and command line required to reproduce each result.
Compare workloads, not marketing labels#
No spreadsheet library is universally fastest for every workbook. Formulas, styles, shared strings, worksheet count, cell density, PHP extensions and the selected API all affect the result. Use this page to benchmark the exact files and operations your application performs.
Use a fair benchmark matrix#
| Benchmark control | MNB PHPExcel | PhpSpreadsheet | Why it matters |
|---|---|---|---|
| Package under test | mnb/mnb-phpexcel or mnb/mnb-phpexcel-xlsx | phpoffice/phpspreadsheet | Record exact resolved versions from Composer. |
| Input | The same local XLSX file | The same local XLSX file | Network and disk-cache differences distort results. |
| Sheet | The same worksheet name | The same worksheet name | Different sheets can have radically different dimensions. |
| Data mode | Values only; metadata disabled when not required | setReadDataOnly(true) | Do not compare styled object loading with a values-only stream. |
| Rows | Count the same header and empty-row policy | Count the same header and empty-row policy | Row totals must match before timing is meaningful. |
| Process | One fresh PHP process | One fresh PHP process | Peak memory and opcache state are process-sensitive. |
| Metrics | Seconds, peak MB, rows/sec, result count | Seconds, peak MB, rows/sec, result count | A single elapsed-time number is incomplete. |
Benchmark MNB PHPExcel in a fresh process#
<?php
// benchmark-mnb.php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use Mnb\PHPExcel\MnbExcel;
$path = $argv[1] ?? throw new RuntimeException('Pass an XLSX path.');
$sheetName = $argv[2] ?? null;
$startedAt = hrtime(true);
$rows = 0;
$workbook = MnbExcel::read($path);
$sheet = $workbook->sheetOrActive($sheetName)
->withHeaderRow(1)
->withOptions([
'skip_empty_rows' => true,
'include_cell_metadata' => false,
]);
foreach ($sheet->rows() as $row) {
++$rows;
}
$seconds = (hrtime(true) - $startedAt) / 1_000_000_000;
echo json_encode([
'library' => 'mnb-phpexcel',
'rows' => $rows,
'seconds' => round($seconds, 4),
'rows_per_second' => $seconds > 0 ? round($rows / $seconds, 2) : null,
'peak_memory_mb' => round(memory_get_peak_usage(true) / 1048576, 2),
], JSON_PRETTY_PRINT), PHP_EOL;Benchmark PhpSpreadsheet with equivalent data-only settings#
<?php
// benchmark-phpspreadsheet.php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
$path = $argv[1] ?? throw new RuntimeException('Pass an XLSX path.');
$sheetName = $argv[2] ?? null;
$startedAt = hrtime(true);
$rows = 0;
$reader = new Xlsx();
$reader->setReadDataOnly(true);
if ($sheetName !== null && trim($sheetName) !== '') {
$reader->setLoadSheetsOnly([$sheetName]);
}
$spreadsheet = $reader->load($path);
$sheet = $sheetName !== null && trim($sheetName) !== ''
? $spreadsheet->getSheetByName($sheetName)
: $spreadsheet->getActiveSheet();
if ($sheet === null) {
throw new RuntimeException('Worksheet not found.');
}
foreach ($sheet->getRowIterator(2, $sheet->getHighestDataRow()) as $row) {
if ($row->isEmpty()) {
continue;
}
++$rows;
}
$seconds = (hrtime(true) - $startedAt) / 1_000_000_000;
echo json_encode([
'library' => 'phpspreadsheet',
'rows' => $rows,
'seconds' => round($seconds, 4),
'rows_per_second' => $seconds > 0 ? round($rows / $seconds, 2) : null,
'peak_memory_mb' => round(memory_get_peak_usage(true) / 1048576, 2),
], JSON_PRETTY_PRINT), PHP_EOL;
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);PhpSpreadsheet also provides read filters and cell caching. Include those configurations when they match your production implementation, and disclose them beside the result.
Run repeated tests and publish the median#
php -d opcache.enable_cli=0 benchmark-mnb.php orders.xlsx Orders
php -d opcache.enable_cli=0 benchmark-phpspreadsheet.php orders.xlsx Orders
# Repeat each command at least five times in alternating order.- Publish the XLSX fixture size, sheet name, row count, column count and data types.
- Record PHP, operating-system, CPU, memory and enabled extension versions.
- Show
composer showoutput for both packages. - Verify that both scripts return the same logical row count.
- Report all runs or the median—not only the best run.
- Keep benchmark source code and fixtures available from the repository when licensing permits.
Choose a library from the complete requirement set#
Performance is only one decision factor. Also test formula behavior, styles, charts, legacy formats, encrypted files, framework integration, maintenance expectations and the exact APIs your team must support.
Continue with the fast PHP Excel library for large files guide or the PHPExcel PHP 8 migration guide.