Skip to content
Published on

Modern PHP in 2026 — PHP 8.4 / Laravel 12 / Symfony 7.3 / FrankenPHP / Octane / Livewire / Filament Deep Dive

Authors

1. PHP in 2026 — to everyone who said it was dead (again)

Every year, "PHP is dead" trends. And every year, the server hosting that article runs PHP. Wikipedia, parts of Slack, Facebook's PHP variant Hack, the ~43% of the web that WordPress drives, parts of Shopify's checkout flow, and countless commerce back offices in Korea and Japan all run PHP.

PHP in 2026 didn't just survive on inertia. The language itself is genuinely attractive again.

  • PHP 8.4 (Nov 2024) — Property Hooks (first-class getters/setters), asymmetric visibility, Lazy Objects, new MyClass()->method() chaining
  • Laravel 12 (Feb 2025) — Reverb websocket server, Folio file-based routing, Volt single-file components, Pennant feature flags
  • Symfony 7.3 — Doctrine 3, Mercure push, AssetMapper, new Scheduler
  • FrankenPHP — Caddy-based single-binary runtime with worker mode, Early Hints, and concurrency
  • Octane — Laravel as long-running processes (Swoole / RoadRunner / FrankenPHP adapters)
  • Livewire 3 / Inertia.js — "reactive without Vue/React"
  • Filament 3 / 4 — the de facto Laravel admin standard
  • Pest 3 / PHPUnit 11 / PHPStan 2 / Rector — tests, static analysis, automated migrations

The position of this article is simple. Choosing PHP in 2026 is not "sticking with the past." It is the shortest path to full-stack productivity. This is true for both Korean and Japanese legacy modernization and for fresh greenfield work.

All code in this post targets PHP 8.4 with Laravel 12 / Symfony 7.3. Where 8.3 compatibility matters, it is called out explicitly.


2. PHP 8.4 (Nov 2024) — Property Hooks, asymmetric visibility, Lazy Objects

PHP 8.4 GA'd on November 21, 2024. It is the release that flipped "the language is finished" criticism fastest.

2.1 Property Hooks — getters and setters as first-class citizens

A feature Java, C#, and Kotlin had for decades finally arrived in PHP.

class User
{
    public string $firstName;
    public string $lastName;

    // Virtual property — computed at access time
    public string $fullName {
        get => "{$this->firstName} {$this->lastName}";
        set(string $value) {
            [$this->firstName, $this->lastName] = explode(' ', $value, 2);
        }
    }
}

$u = new User();
$u->fullName = 'Ada Lovelace';
echo $u->fullName; // "Ada Lovelace"
echo $u->firstName; // "Ada"

Previously you used __get / __set magic methods, which broke IDE autocomplete and confused static analyzers. Now the property looks like a property, and PHPStan/Psalm reason about it as such.

2.2 Asymmetric Visibility

"Public read, private write" in one line.

class Account
{
    // Public read + private set
    public private(set) int $balance = 0;

    public function deposit(int $amount): void {
        $this->balance += $amount;
    }
}

$a = new Account();
$a->deposit(100);
echo $a->balance; // 100 OK
$a->balance = 9999; // Error: cannot set from outside

The "final field + getter" boilerplate from Java disappears.

2.3 Lazy Objects

The feature ORMs and DI containers wanted most. Build an empty shell, materialize on first access.

$reflector = new ReflectionClass(HeavyService::class);
$lazy = $reflector->newLazyGhost(function (HeavyService $instance): void {
    $instance->__construct(/* expensive deps */);
});

// $lazy is uninitialized
$lazy->doSomething(); // the init callback runs at this moment

Doctrine, Symfony DI, and Laravel's container are all in the middle of trimming their custom proxy code on top of 8.4 Lazy Objects.

2.4 new MyClass()->method() — one pair of parens removed

// Through PHP 8.3
$dt = (new DateTime('now'))->format('Y-m-d');

// PHP 8.4
$dt = new DateTime('now')->format('Y-m-d');

A small win, but the code reads notably cleaner.

2.5 New array helpers and HTML5 parser

array_find($users, fn($u) => $u->isAdmin());
array_find_key($users, fn($u) => $u->name === 'Ada');
array_any($users, fn($u) => $u->isActive());
array_all($users, fn($u) => $u->isVerified());

$dom = Dom\HTMLDocument::createFromString('<p>Hello</p>');

PHP 8.4 is another big leap, on top of 8.0 (JIT / Union types), 8.1 (enums / readonly), 8.2 (readonly class), and 8.3 (typed const).


3. Laravel 12 (Feb 2025) — Reverb / Folio / Volt / Pennant

Laravel 12 shipped February 24, 2025. It answers "what else could a framework possibly add?" with: a lot.

3.1 Reverb — Laravel's first-party WebSocket server

After Pusher and Soketi, Laravel finally has its own WebSocket server. Built on ReactPHP; combined with FrankenPHP or Octane, a single host handles tens of thousands of concurrent connections.

composer require laravel/reverb
php artisan reverb:install
php artisan reverb:start
// app/Events/MessageSent.php
class MessageSent implements ShouldBroadcast
{
    public function __construct(public Message $message) {}

    public function broadcastOn(): array {
        return [new PrivateChannel("chat.{$this->message->room_id}")];
    }
}

One line on the front with Laravel Echo:

Echo.private(`chat.${roomId}`).listen('MessageSent', (e) => {
  appendMessage(e.message);
});

3.2 Folio — file-system routing

Next.js / Nuxt-style file routing for Laravel. Files under resources/views/pages/ are routes.

resources/views/pages/
├── index.blade.php/
├── dashboard.blade.php/dashboard
└── users/
    ├── index.blade.php/users
    └── [id].blade.php/users/{id}
// resources/views/pages/users/[id].blade.php
<?php
use function Laravel\Folio\name;
use App\Models\User;

name('users.show');

$user = User::findOrFail($id);
?>

<h1>{{ $user->name }}</h1>

You never touch web.php to add a page. Perfect for small side projects and admin panels.

3.3 Volt — Livewire 3 single-file components

Vue-SFC-style Livewire. PHP logic and Blade template live in one file.

<?php
use function Livewire\Volt\{state, computed};

state(['count' => 0]);

$increment = fn () => $this->count++;
?>

<div>
    <button wire:click="increment">+</button>
    <span>{{ $count }}</span>
</div>

Folio + Volt is the new "fastest way to ship one screen in Laravel."

3.4 Pennant — first-class feature flags

use Laravel\Pennant\Feature;

Feature::define('new-checkout', fn (User $user) => $user->isInternal());

if (Feature::active('new-checkout')) {
    return view('checkout.v2');
}

You can stand up DB-backed feature flags in a week without LaunchDarkly.

3.5 Plus — new starter kits, Workflows, Vite 6

Laravel 12 ships official starter kits for React / Vue / Livewire, a Workflows engine, Vite 6, and Tailwind 4 out of the box. A single laravel new now gets you to auth, admin, and billing.


4. Symfony 7.3 — Doctrine 3 + Mercure + AssetMapper

Symfony is the other right answer — more explicit, more component-oriented, and the de facto enterprise PHP framework.

4.1 The 7.x line

  • 7.0 (Nov 2023) — requires PHP 8.2+
  • 7.1 (May 2024) — new Asset Mapper integration
  • 7.2 (Nov 2024) — JSON Streamer, Profiler improvements
  • 7.3 (May 2025) — Doctrine 3 stable support, first-class Mercure adapter

4.2 Doctrine ORM 3 + DBAL 4

#[ORM\Entity]
class Product
{
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
    public int $id;

    #[ORM\Column(length: 200)]
    public string $name;

    #[ORM\Column(type: 'decimal', precision: 10, scale: 2)]
    public string $price;
}

Doctrine 3 supports enums, readonly, and asymmetric visibility natively, and aligns nicely with PHP 8.4 Property Hooks.

4.3 Mercure — server-to-browser push

When a WebSocket is overkill, use the Mercure hub built on Server-Sent Events. First-class in Symfony 7.

public function publish(HubInterface $hub): Response {
    $hub->publish(new Update(
        '/orders/42',
        json_encode(['status' => 'shipped']),
    ));
    return new Response();
}

4.4 AssetMapper — "frontend without Node"

php bin/console importmap:require bootstrap

You can ship an SPA-ish front end via importmap and native ES modules without Webpack/Vite. Especially fits admin tools and internal apps.

4.5 Scheduler and Messenger

#[AsSchedule('default')]
class MainSchedule implements ScheduleProviderInterface
{
    public function getSchedule(): Schedule {
        return (new Schedule())->add(
            RecurringMessage::cron('0 3 * * *', new DailyReport()),
        );
    }
}

Cron + queue + workflow into one component. The Symfony answer to Laravel's schedule:run + Horizon.


5. FrankenPHP — a single-binary PHP runtime on Caddy

FrankenPHP, started in 2022 by Kévin Dunglas (author of API Platform and Mercure), is a Go binary that embeds the PHP interpreter inside the Caddy web server. 1.0 GA'd in 2024 and as of 2026 is officially supported by both Laravel and Symfony.

5.1 Why it's a big deal

The traditional PHP stack:

nginx → php-fpm → PHP
Three processes, three config files

FrankenPHP:

single frankenphp binary → PHP
HTTPS, HTTP/3, metrics, static files, PHP execution — all one process

5.2 Worker mode — long-running PHP

The killer feature is worker mode. PHP isn't booted per request; a bootstrapped worker runs a request loop.

// public/worker.php
require __DIR__ . '/../vendor/autoload.php';
$kernel = (require __DIR__ . '/../bootstrap/app.php')
    ->handleRequest(Request::capture());

$handler = static function () use ($kernel) {
    // Per-request handler — Octane calls this internally
    return $kernel->handle(Request::capture());
};

\frankenphp_handle_request($handler);
# Caddyfile
{
    frankenphp {
        worker ./public/worker.php
    }
}

example.com {
    root * public/
    php_server
}

When per-request bootstrap disappears, Laravel response times routinely drop by 50–80%.

5.3 Early Hints (103) — the trick that actually makes things faster

// Send 103 Early Hints with CSS/JS preload before the body is ready
return response()
    ->withHeaders(['Link' => '</css/app.css>; rel=preload; as=style'])
    ->earlyHints();

The browser starts loading CSS before the body arrives. LCP typically improves by 200–400ms.

5.4 Embed mode — single-binary deployment

frankenphp build packages the PHP interpreter + your app + Caddy into one binary. One scp to ship. You don't even need Docker.

frankenphp build --output ./myapp
scp ./myapp user@server:/srv/myapp
ssh user@server './myapp run'

6. Laravel Octane — Swoole / RoadRunner / FrankenPHP

Octane is the official adapter that runs Laravel as long-running processes. A worker pool stays in memory after one bootstrap and reuses the container per request.

6.1 Three backends

BackendBuilt onStrengthsWatch out for
SwooleC extensionCoroutines, peak performanceMemory-leak debugging is tricky
RoadRunnerGoStability, explicit worker modelNo coroutines
FrankenPHPCaddy/GoSingle binary, Early HintsNewest of the three
composer require laravel/octane
php artisan octane:install --server=frankenphp
php artisan octane:start --workers=8

6.2 Two things Octane changes

  1. Boot time — if Laravel boots in 80ms, after the first worker boot subsequent requests cost 0ms of boot.
  2. Singleton lifetime — container singletons survive across requests. This is the trap. Per-request state bound into a singleton leaks across requests and becomes a security incident.
// DANGEROUS — never pin a user request object into a singleton
$this->app->singleton('user', fn () => Auth::user()); // BAD

// SAFE — rebuild every request
$this->app->scoped('user', fn () => Auth::user());     // GOOD

php artisan octane:reload performs zero-downtime worker restart. One line after a code deploy.


7. RoadRunner + Spiral — a Go-based runner and a framework on top

RoadRunner, by Spiral Scout, is a Go-based PHP application server started in 2018. As of 2026 the v2025 line is running in stable production.

7.1 What sets RoadRunner apart

  • Worker pool managed in Go; requests are dispatched to PHP workers over gRPC
  • HTTP, gRPC, queues (Beanstalk / SQS / AMQP / NATS), job scheduler, KV all in one process
  • Metrics exported first-class via OpenTelemetry
# .rr.yaml
version: '3'

server:
  command: 'php worker.php'

http:
  address: '0.0.0.0:8080'
  pool:
    num_workers: 8

jobs:
  pipelines:
    high:
      driver: memory
      config:
        priority: 1

7.2 Spiral — PHP's "Go-style" framework

Spiral is the framework from the team that built RoadRunner. Unlike Laravel/Symfony, it was designed from day one for long-running PHP.

  • DI is PSR-11
  • ORM is Cycle ORM (DataMapper, an alternative to Doctrine)
  • Routing via attributes
  • Queues, gRPC services, and workflows (first-class Temporal integration) are built in
#[Route(route: '/users/<id:int>', methods: 'GET')]
public function show(int $id, ORM $orm): array {
    return $orm->getRepository(User::class)->findByPK($id)->toArray();
}

Compelling for those who find "Laravel too magical, Symfony too heavy."

7.3 Hyperf — the coroutine framework from China

Hyperf is a Swoole-coroutine-based async framework. Inside China it rivals Laravel in mindshare, and parts of the Japanese and Korean game-server backend scenes have adopted it.

#[AutoController]
class UserController {
    #[GetMapping(path: '/users/{id}')]
    public function show(int $id): array {
        return User::find($id)->toArray();
    }
}

With coroutines, Promise.all-style patterns feel as natural as in Node.js.


8. Livewire 3 + Inertia.js — Laravel reactive / SPA

Two answers to "SPA-feel UX without React or Vue."

8.1 Livewire 3 — server components, PHP edition

Livewire 3 was largely rewritten in 2023. It integrates deeply with Alpine.js and behaves similarly to React Server Components.

// app/Livewire/Counter.php
class Counter extends Component
{
    public int $count = 0;

    public function increment(): void {
        $this->count++;
    }

    public function render(): View {
        return view('livewire.counter');
    }
}
{{-- resources/views/livewire/counter.blade.php --}}
<div>
    <button wire:click="increment">+</button>
    <span>{{ $count }}</span>
</div>

The server renders an HTML fragment per interaction. You burn a bit more network in exchange for almost zero JS code. Best in class for admin and internal tools.

8.2 Inertia.js — SPA on top of Laravel/Rails

Inertia is a "full-stack adapter for SPAs." Your backend (Laravel/Rails/Django) controller returns a Vue/React/Svelte component plus its props.

// Controller
public function index() {
    return Inertia::render('Users/Index', [
        'users' => User::paginate(20),
    ]);
}
<!-- resources/js/Pages/Users/Index.vue -->
<script setup>
defineProps({ users: Object });
</script>

<template>
  <ul>
    <li v-for="u in users.data" :key="u.id">{{ u.name }}</li>
  </ul>
</template>

You don't have to build a REST API. Routing, auth, and permissions stay on the backend.

8.3 How to choose

SituationPick
Admin, internal tools, small SaaSLivewire 3 (or Filament)
Real SPA, fully interactive UIInertia.js + Vue/React
Mostly static + sprinkles of interactivityAlpine.js only

9. Filament — the de facto Laravel admin standard

Filament, by Dan Harrin, is a "Laravel admin-panel generator." It exploded after v2 (2022), grew through v3 (2024) and v4 (2025). In 2026, Laravel admin is essentially Filament.

9.1 What you get

  • Resource (CRUD) generator — php artisan make:filament-resource User
  • Tables, forms, widgets, notifications as composable components
  • Multi-tenancy (subdomain, path prefix)
  • Roles / permissions (integrated with Spatie packages)
  • Runs on top of Livewire 3
class UserResource extends Resource
{
    protected static ?string $model = User::class;

    public static function form(Form $form): Form {
        return $form->schema([
            TextInput::make('name')->required(),
            TextInput::make('email')->email()->required(),
            Select::make('role')->options([
                'admin' => 'Admin',
                'user'  => 'User',
            ]),
        ]);
    }

    public static function table(Table $table): Table {
        return $table
            ->columns([
                TextColumn::make('name')->searchable(),
                TextColumn::make('email')->copyable(),
                TextColumn::make('created_at')->dateTime(),
            ])
            ->filters([
                SelectFilter::make('role'),
            ])
            ->actions([
                EditAction::make(),
                DeleteAction::make(),
            ]);
    }
}

In under 20 lines you get search, filters, pagination, and actions. Compared to Django Admin, Filament wins on visual polish and customization freedom.

9.2 Beyond admin — as an app builder

Filament is no longer just for admin. Through Panels, you can build customer dashboards, partner portals, and ops tools from the same codebase.

PanelAudienceURL
adminInternal admins/admin
partnerB2B partners/partner
customerEnd customers/app

10. Statamic — the flat-file CMS

Statamic is the answer for Laravel folks tired of WordPress. Content lives in Markdown + YAML files, not a database.

10.1 What's good about it

  • Files ARE content → committed to Git → code review IS content review
  • Built on Laravel → packages, queues, auth all reusable
  • Built-in Control Panel is clean
  • Antlers template engine + Blade both supported
  • Headless export to GraphQL/REST
# content/collections/articles/2026-05-16.hello.md
---
id: a1b2c3
title: 'Hello, Statamic'
author: youngju
---
# Markdown body
Hello, world.

10.2 Where it fits

  • Marketing sites, blogs, documentation sites
  • Low-frequency content changes with high design freedom
  • Teams that want a Git-driven workflow (review articles as PRs)

The difference from WordPress is clear. Statamic is developer-first and code-first; WordPress is editor-first and UI-first.


11. Tooling — Pest / PHPUnit 11 / PHPStan 2 / Psalm / Rector

11.1 Pest 3 — expressive test runner

Pest layers a "Jest-like DSL" on top of PHPUnit. 3.0 in 2024, 4.x in 2025.

// tests/Feature/UserTest.php
use App\Models\User;

it('creates a user', function () {
    $user = User::factory()->create(['name' => 'Ada']);
    expect($user->name)->toBe('Ada');
});

test('admin can list users')
    ->actingAs(User::factory()->admin()->create())
    ->get('/admin/users')
    ->assertOk();

Browser tests are now first-class (pest --browser). From Pest 4 they run on Playwright.

11.2 PHPUnit 11

Still the industry standard. Pest also runs on PHPUnit under the hood.

final class UserTest extends TestCase
{
    public function testItCreatesUser(): void {
        $user = User::factory()->create();
        $this->assertNotNull($user->id);
    }
}

In 11.x, attributes (#[Test], #[DataProvider], ...) have become the default style.

11.3 PHPStan 2 vs Psalm

ItemPHPStan 2Psalm
MaintainerOndřej MirtesVimeo (now community)
StrengthsFast analysis, large ecosystemStricter inference, taint analysis
Laravel fitExcellent (Larastan)Moderate
2026 momentumStrongSlowed

Most new Laravel/Symfony projects start with PHPStan 2 + Larastan.

composer require --dev phpstan/phpstan larastan/larastan
vendor/bin/phpstan analyse --level=8 app/

A clean run at level 8 (max) earns you the label "type-safe PHP."

11.4 Rector — automated refactors

Rector is an AST-based automated migration tool. It performs major upgrades from PHP 7 to 8, Laravel 10 → 11 → 12, Symfony 6 → 7 in one shot.

// rector.php
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\LevelSetList;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/app'])
    ->withPhpSets(php84: true)
    ->withSets([LevelSetList::UP_TO_PHP_84]);
vendor/bin/rector process

The single biggest prescription for the PHP 5/7 legacy code people "are too scared to upgrade."


12. Hosting — Forge / Vapor / Cloud

Laravel has finished its vertical integration: language → framework → tooling → hosting.

12.1 Forge — VPS provisioning SaaS

  • Launched 2014, the oldest Laravel hosting tool
  • Auto-provisions VPSes on DigitalOcean / AWS / Linode / Vultr / Hetzner
  • nginx + PHP-FPM + Redis + Supervisor + Let's Encrypt configured automatically
  • First-class FrankenPHP support since 2025

12.2 Vapor — serverless (AWS Lambda)

  • Runs Laravel on AWS Lambda (PHP via Bref)
  • Cold starts average 300–500ms
  • Queues on SQS, DB on RDS Aurora, cache on Redis (ElastiCache)
  • Great for "spiky-traffic" services

12.3 Cloud — managed hosting for the Laravel 11/12 era

Laravel Cloud was announced in 2024 and went GA in 2025 as a "Vercel-style" managed hosting.

  • Git push → auto build + deploy + domain + SSL
  • FrankenPHP worker mode as the default runtime
  • Postgres / Redis / queues / job scheduler in one dashboard
  • Regions: US / EU / Asia (Singapore), more being added

Vercel hosts Next.js first-class; Cloud hosts Laravel first-class.

SituationPick
Stable traffic, cost-sensitiveForge + VPS
Spiky traffic, deep AWS integrationVapor
"Don't make me think, just deploy"Cloud

13. Korea / Japan — Woowa Brothers, Kakao, pixiv, Cookpad, Mercari

Where do real companies actually use PHP? Let's look at Korean and Japanese examples.

13.1 Korea

  • Woowa Brothers (Baemin) — early back-office systems were PHP; some admin and internal tools still are. New systems are Java/Kotlin, but the in-house admin builder explored Filament — an INFCON 2025 talk mentioned this evaluation.
  • Kakao — some ad / marketing landing pages, internal tools. Parts of Kakao Games' back office are also PHP.
  • GS Shop, eMart Mall, 11st and similar Korean commerce back offices still run substantial PHP / CodeIgniter / CakePHP code.
  • New-startup PHP adoption has declined, but PHP still dominates the agency / marketing / CMS market.

13.2 Japan

  • pixiv — Japan's illustration SNS, PHP since the beginning. Internal tools and parts of the main product still run PHP. PHP 8.3 migration cases from 2024 and PHP 8.4 cases from 2025 have been presented at PHPerKaigi.
  • Cookpad — long known as a Ruby on Rails shop, but acquired subsidiaries and experimental products carry PHP.
  • Mercari — the original monolith was PHP (Symfony). After the microservices push it became Go-centric, but parts of the back office and supporting systems remain PHP.
  • Cookpad Inc., CyberAgent, GMO Pepabo, PIXTA — countless PHP stories appear at PHPerKaigi and PHP Conference Japan each year.
  • Japan has a tighter PHP community and more active conferences than Korea. PHPerKaigi and PHP Conference Japan each draw hundreds of attendees.

13.3 Common patterns

  • "New systems in Go / Kotlin / TypeScript; admin, CMS, marketing, legacy stays on PHP"
  • What's truly dying isn't PHP, it's legacy frameworks (CodeIgniter 3, CakePHP 2, Symfony 2/3)
  • PHP 8.4 + Laravel 12 + FrankenPHP is the shortest path to modernize that legacy

14. Who should pick PHP — a 2026 decision guide

It's not "the language" but "the situation" that decides.

14.1 PHP is the right answer when

  • A solo dev or small team needs to ship a SaaS fast → Laravel 12 + Filament + Forge
  • Internal admin, ops, back office → Filament alone
  • Marketing site + blog → Statamic
  • Modernizing legacy PHP → PHP 8.4 + Rector + Pest + Octane
  • UI you want with as little JS as possible → Livewire 3 (or Inertia)
  • A WordPress alternative → Statamic or headless + Laravel API

14.2 PHP is the wrong choice when

  • Ultra-low latency (sub-1ms), hundreds of thousands of concurrent connections → Go / Rust / Elixir
  • Data science, ML training → Python
  • Mobile native, game clients → Swift / Kotlin / C++ / C#
  • AWS Lambda where cold start is critical → Node.js / Rust

14.3 The "modern PHP" stack — 2026 full-stack SaaS recommendation

PHP 8.4
Laravel 12
FrankenPHP (worker mode) + Octane
Livewire 3 + Volt + Filament 4
Postgres 16 + Redis 7
Pest 3 + PHPStan 2 (level 8) + Rector
Laravel Cloud (or Forge + Hetzner)

On this stack, "one dev ships a billing-complete SaaS in a month" is no longer hyperbole.

14.4 One last thing

PHP in 2026 no longer suffers the punchlines PHP in 2016 did. The language got better, the ecosystem got tighter, the hosting got smoother. In Korea and Japan, PHP has become both "the language that keeps legacy alive" and "the language that ships new full-stack apps fastest."

The line after "PHP refuses to die" needs a rewrite. "PHP is not just alive — it is attractive again."


References