Seven PHP frameworks, four measurements
Cold request, load test, OPcache preload and the Laravel preload curve: the measured cost of seven PHP frameworks on a single page.
4.4×
Empty route, req/s
gap between the fastest and the slowest
Slim 25,975, Laravel 5,966 req/s. Once the database joins in, the gap shrinks to 3.7×.
Footprint
Files loaded per request
files
- Phalcon7
- Yii262
- Slim79
- CodeIgniter96
- Symfony224
- Laminas269
- Laravel359
Footprint
Cold first request
ms
- Phalcon2.2
- Slim7.9
- Yii217.4
- CodeIgniter22.2
- Laminas27.7
- Symfony35.7
- Laravel72.2
Load test
Throughput on an empty route
req/s
- Slim25,975
- Yii219,834
- Phalcon15,021
- Symfony13,067
- Laminas8,349
- CodeIgniter6,431
- Laravel5,966
Load test
Req/s by scenario
| Framework | Empty route | Template | DB single row | DB 20 rows |
|---|---|---|---|---|
| Slim | 25,975 | 22,780 | 14,443 | 4,551 |
| Yii2 | 19,834 | 16,995 | 9,366 | 3,245 |
| Phalcon | 15,021 | 10,563 | 5,222 | 2,040 |
| Symfony | 13,067 | 9,355 | 6,972 | 3,060 |
| Laminas | 8,349 | 7,419 | 5,421 | 2,874 |
| CodeIgniter | 6,431 | 5,557 | 4,527 | 2,494 |
| Laravel | 5,966 | 5,290 | 3,887 | 1,293 |
Load test
The gap narrows as work is added
- 3.7×Gap at a single DB row4.4× on an empty route, 3.5× at 20 rows
- 1.3×Phalcon / LaravelAt a single DB row, versus 2.5× on an empty route
- 0-7%Cost of routingLoss compared to an empty route
- 1-8%Cost of middlewareWhen a five-layer chain is added
Load test
Latency on a JSON response
| Framework | p50 | p95 | p99 |
|---|---|---|---|
| Slim | 0.25 ms | 0.43 ms | 0.53 ms |
| Yii2 | 0.35 ms | 0.59 ms | 0.73 ms |
| Phalcon | 0.46 ms | 0.73 ms | 0.94 ms |
| Symfony | 0.58 ms | 0.89 ms | 0.96 ms |
| Laminas | 0.88 ms | 1.52 ms | 2.23 ms |
| CodeIgniter | 1.16 ms | 1.84 ms | 1.98 ms |
| Laravel | 0.75 ms | 1.97 ms | 2.59 ms |
−63%
Laravel
throughput taken by the default web group
Choosing a framework can open a gap of up to 4×, but a single default middleware group can take away 63%.
Laravel
Web group on and off
| Route | Req/s | p50 | p99 |
|---|---|---|---|
| No group | 5,858 | 1.32 ms | 2.88 ms |
| Default web group | 2,176 | 1.73 ms | 71.89 ms |
OPcache preload
Cold request: before and after preload
| Framework | No preload | Best preload | Gain | fpm cost |
|---|---|---|---|---|
| Laravel | 76.31 ms | 13.98 ms | 5.5× | +2,340 ms |
| Symfony | 35.58 ms | 2.50 ms | 14.2× | −40 ms |
| Laminas | 26.70 ms | 3.81 ms | 7.0× | −7 ms |
| CodeIgniter | 20.75 ms | 3.13 ms | 6.6× | −12 ms |
| Yii2 | 16.98 ms | 4.80 ms | 3.5× | +13 ms |
| Slim | 7.46 ms | 1.86 ms | 4.0× | +28 ms |
| Phalcon | 2.68 ms | 1.99 ms | 1.3× | +43 ms |
OPcache preload
Preload is not a setting, it is a maintenance job
- 2/7Official preload fileOnly in Symfony and CodeIgniter
- 14.2×Symfony's gainFrom 35.58 ms to 2.50 ms
- 2.3 sLaravel's deploy costIn return for a 62 ms gain per visitor
- 1.3×PhalconNegative control: 3 files
Laravel preload curve
Cold request as more files are preloaded
cold request, ms
Median values; the filters are specific to this application.
Laravel preload curve
The sweet spot is at 2,809 files
- 12.77 msCold request at the sweet spot−81% compared to 68.37 ms without preload
- +1,132 msfpm readiness costFrom 382 ms to 1,514 ms
- 15.7 msGain from the critical 123 filesEight times what the 1,912 files deliver
- 1.8 msGain from the last 1,912 files654 ms of cost per millisecond gained
As you read
The limits of these numbers
- EnvironmentThe load test ran in a Docker Desktop VM; absolute values do not represent bare metal, and the fast candidates are, if anything, under-reported.
- ScopeJIT was off, worker mode was not measured. Slim has no data layer or template engine of its own.
- ColdCold means an empty OPcache. A single shot strays from the median: Symfony takes 76.5 ms in a single shot, against a median of 35.58 ms.
- ConsistencyZero non-200 responses across 546 load measurements; in 150 samples the worst value is 84% of the best.