| Framework | Version | Min PHP | Architecture | Best suited to | Repository, licence |
|---|---|---|---|---|---|
| Laravel 2,157 | 13.33.0 | 8.3 | Full-stack MVC | Full web apps | laravel/framework, MIT |
| Symfony 6,093 | 8.1.7, LTS 7.4 | 8.4, LTS 8.2 | Components, full stack | Long-lived systems | symfony/symfony, MIT |
| CodeIgniter 23,248 | 4.7.4 | 8.2 | Light MVC | Shared hosting | codeigniter4/CodeIgniter4, MIT |
| CakePHP 43,091 | 5.4.2 | 8.2 | Convention MVC | Schema-driven apps | cakephp/cakephp, MIT |
| Yii 2 41,671 / Yii3 | 2.0.55 / 1.4.0 | 7.4 / 8.2 | MVC / packages | Existing Yii apps | yiisoft/yii2, yiisoft/app, BSD-3-Clause |
| Laminas / Mezzio | 3.8.0 / 3.28.1 | 8.1 / 8.2 | MVC / middleware | Standards-first APIs | laminas, mezzio/mezzio, BSD-3-Clause |
| Slim 32,516 | 4.15.3 | 7.4 | Micro, PSR-15 | Small APIs | slimphp/Slim, MIT |
| Lumen 2,157 | 11.2.0 | 8.2 | Micro (retired) | No new projects | laravel/lumen-framework, MIT |
| Phalcon 730,690 | 5.22.0 | 8.1 | C extension | Servers you control | phalcon/cphalcon, BSD-3-Clause |
For a fair check, the bookshop route also went into a copy of the Laravel skeleton, as a plain-text Route::get('/hello', ...) in routes/web.php. This loop serves each app in turn:
for app in symfony slim codeigniter laravel phalcon; do
opts=(); [ $app = phalcon ] && opts=(-d extension=$PWD/phalcon/phalcon.so)
php "${opts[@]}" -S 127.0.0.1:8322 -t $app/public > /dev/null 2>&1 &
pid=$!; sleep 1
curl -s http://127.0.0.1:8322/hello
kill $pid; wait $pid
doneHello, bookshop, from Symfony 8.1.7 Hello, bookshop, from Slim 4.15.1 Hello, bookshop, from CodeIgniter 4.7.4 Hello, bookshop, from Laravel 13.33.0 Hello, bookshop, from Phalcon 5.22.0
for app in laravel symfony slim codeigniter; do
printf '%-12s %4s packages %s\n' $app "$(composer -d $app show | wc -l)" \
"$(du -sh $app/vendor | cut -f1)"
donelaravel 109 packages 69M symfony 32 packages 11M slim 11 packages 1.3M codeigniter 33 packages 28M
Those are the installers' defaults, test tools included; composer install --no-dev -o cut Laravel to 76 packages and 43M and CodeIgniter to 3 and 5.7M. For timing, each app ran in production mode after its own cache step (php artisan optimize, Symfony's cache:clear for prod, php spark optimize). A script, timing.sh, started a fresh php -S with OPcache five times per app, timed the first request (cold) and the next 20 (warm) with curl 3,008 , and printed medians:
bash timing.shlaravel cold 204.0 ms warm 5.7 ms symfony cold 83.7 ms warm 3.0 ms slim cold 19.3 ms warm 0.8 ms codeigniter cold 51.3 ms warm 1.5 ms phalcon cold 1.4 ms warm 0.7 ms
These are proportions from one WSL2 6 machine, PHP's development server and a route that does nothing; a second run landed within 2 ms of every figure. Laravel also pays for a session its web group starts in SQLite 4,756 . Cold requests differ most because they are spent compiling framework code, which Phalcon skips; once OPcache holds it, every framework answers in a few milliseconds, less than a single real page's database work (MySQL).