Menjalankan Symfony di atas FrankenPHP: paket frankenphp/symfony- runtime, variabel APP_RUNTIME untuk worker mode, HTTP cache, dan audit kompatibilitas worker dengan igor-php agar state leak tidak menyerang di produksi.

Setelah episode 6 membahas Laravel, episode ini berpindah ke framework besar kedua ekosistem PHP: Symfony. FrankenPHP lahir dari tangan Kévin Dunglas — anggota core team Symfony — jadi wajar jika integrasinya sangat dalam. Kita akan membahas runtime/frankenphp-symfony, variabel APP_RUNTIME, HTTP cache, dan audit worker dengan igor.
Mengapa penting? Symfony adalah framework yang sangat modular dan ketat. Di mode worker, ketelitiannya menjadi keuntungan: kernel Symfony memang dirancang untuk di-reset antar request, dan integrasi resminya memanfaatkan itu. Hasilnya, aplikasi Symfony di worker mode bisa melayani ribuan request per detik dengan pola kode yang tetap terstruktur.
Sejak Symfony 7.4, FrankenPHP worker mode didukung secara native — tanpa paket tambahan. Kalian cukup mengaktifkan worker di Caddyfile:
localhost
root public/
php_server {
worker ./public/index.php
}Symfony akan mendeteksi bahwa ia berjalan di FrankenPHP dan menjalankan runtime worker secara otomatis. Ini jalur paling bersih untuk proyek baru.
runtime/frankenphp-symfony (Symfony Lama)Untuk Symfony di bawah 7.4, gunakan paket PHP Runtime:
composer require runtime/frankenphp-symfonyLalu definisikan runtime lewat environment variable APP_RUNTIME:
docker run \
-e FRANKENPHP_CONFIG="worker ./public/index.php" \
-e APP_RUNTIME="Runtime\\FrankenPhpSymfony\\Runtime" \
-v $PWD:/app \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphpPerhatikan escaping ganda \\ — ini adalah nilai env var, jadi backslash harus ditulis ganda. APP_RUNTIME memberi tahu Symfony bahwa bootstrap harus dilakukan oleh runtime FrankenPHP, bukan runtime console/web standar.
Note
Gunakan integrasi resmi (native atau runtime package) untuk Symfony di worker mode. Jangan menulis loop frankenphp_handle_request() manual di atas Symfony — kernel, event system, dan profiler Symfony perlu di-reset dengan benar antar request, dan runtime resmi sudah menangani itu.
Symfony memiliki komponen HTTP cache (HttpCache kernel) yang menyimpan response. Di worker mode, cache ini bisa hidup di memori — jauh lebih cepat daripada file cache di disk. Pastikan cache diaktifkan sesuai environment:
{
frankenphp {
worker {
file /app/public/index.php
env APP_ENV prod
env APP_DEBUG 0
}
}
}
localhost {
root public/
php_server {
worker ./public/index.php
}
}Dengan APP_ENV=prod, Symfony mengaktifkan cache class, cache HTTP, dan optimasi produksi lainnya — kombinasi ideal dengan worker mode.
Symfony menyediakan tool audit untuk menemukan state leak sebelum mereka menggigit di produksi. Igor PHP adalah linter statis yang memindai proyek (termasuk vendor/) untuk:
ResetInterface.exit()/die() — yang akan mematikan seluruh worker!composer require --dev igor-php/igor-php
vendor/bin/igor-php .Jalankan di CI sebelum deploy. Jika ada temuan, perbaiki dulu sebelum beralih ke worker mode.
Danger
exit() atau die() di dalam kode yang dieksekusi per-request akan menghentikan seluruh proses worker — bukan hanya request itu. Ini adalah bug paling merusak di worker mode. Igor PHP mendeteksi keduanya; jalankan secara rutin.
Service Symfony yang menyimpan state per-request (misal holder token auth, current request context) harus di-reset antar request. Implementasikan ResetInterface:
<?php
namespace App\Service;
use Symfony\Contracts\Service\ResetInterface;
final class RequestContextHolder implements ResetInterface
{
private array $data = [];
public function set(string $key, mixed $value): void
{
$this->data[$key] = $value;
}
public function get(string $key): mixed
{
return $this->data[$key] ?? null;
}
public function reset(): void
{
$this->data = [];
}
}Kernel Symfony memanggil reset() pada semua service ber-tag kernel.reset setelah setiap request — state kalian kembali bersih tanpa menulis ulang logika aplikasi.
Untuk proyek Symfony, jalur paling praktis adalah Symfony Docker — setup resmi yang dikelola penulis FrankenPHP dengan worker mode, HTTPS otomatis, HTTP/3, dan hot reload siap pakai:
git clone https://github.com/dunglas/symfony-docker
cd symfony-docker
docker compose up --waitBuka https://localhost — aplikasi Symfony berjalan di worker mode dengan cache produksi. Kita bedah struktur Docker-nya di episode 19.
Pada episode 7 ini, kalian telah menjalankan Symfony di atas FrankenPHP.
Inti yang harus dibawa pulang:
runtime/frankenphp-symfony + APP_RUNTIME.APP_ENV=prod + APP_DEBUG=0 mengaktifkan HTTP cache dan optimasi produksi.exit()/die(), dan superglobal writes — jalankan di CI.ResetInterface.Di episode 8 selanjutnya kita membahas lapisan yang sering diremehkan tapi menentukan performa: static files, gzip, dan HTTP caching — mengoptimalkan aset CSS/JS/image di Caddyfile dengan encode, precompressed, dan header cache. Sampai jumpa di episode 8!