MNB PHPExcelDeveloper Guide
Migration guides

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

LevelAdvancedReading time16 minPackagemnb/mnb-phpexcel
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 controlMNB PHPExcelPhpSpreadsheetWhy it matters
Package under testmnb/mnb-phpexcel or mnb/mnb-phpexcel-xlsxphpoffice/phpspreadsheetRecord exact resolved versions from Composer.
InputThe same local XLSX fileThe same local XLSX fileNetwork and disk-cache differences distort results.
SheetThe same worksheet nameThe same worksheet nameDifferent sheets can have radically different dimensions.
Data modeValues only; metadata disabled when not requiredsetReadDataOnly(true)Do not compare styled object loading with a values-only stream.
RowsCount the same header and empty-row policyCount the same header and empty-row policyRow totals must match before timing is meaningful.
ProcessOne fresh PHP processOne fresh PHP processPeak memory and opcache state are process-sensitive.
MetricsSeconds, peak MB, rows/sec, result countSeconds, peak MB, rows/sec, result countA single elapsed-time number is incomplete.

Benchmark MNB PHPExcel in a fresh process#

benchmark-mnb.php
<?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#

benchmark-phpspreadsheet.php
<?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#

Terminal
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 show output 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.