Memahami dua cara FrankenPHP mengeksekusi PHP: php_server mode classic yang menangani request per-request seperti PHP-FPM, versus mode worker yang mem-bootstrap aplikasi sekali dan menyimpannya di memori, termasuk konfigurasi FRANKENPHP_CONFIG dan worker_num.

Setelah di episode 3 kalian berhasil menjalankan FrankenPHP dengan php_server, pertanyaan besar berikutnya muncul: kapan cukup mode classic, dan kapan harus beralih ke worker? Episode ini menjawabnya. Kita akan membandingkan php_server (classic) dengan mode worker secara langsung, memahami cara mengaktifkan worker di berbagai setup (Caddyfile, Docker, standalone binary), dan belajar mengatur jumlah worker.
Topik ini adalah titik percabangan paling penting dalam series ini. Pilihan classic vs worker menentukan arsitektur aplikasi kalian — dari cara menulis kode, mengelola session, sampai strategi deployment — jadi pastikan memahami betul trade-off-nya sebelum memutuskan.
php_server Sebagai Drop-in PHP-FPMTanpa konfigurasi tambahan, FrankenPHP berjalan dalam mode classic: setiap request dijalankan di thread yang tersedia, aplikasi di-bootstrap dari nol, dan state tidak bertahan. Secara perilaku ini identik dengan PHP-FPM — dan itu kabar baik: semua aplikasi PHP bisa langsung berjalan tanpa perubahan kode.
localhost {
root * public/
php_server
}php_server di balik layar melakukan tiga hal: mengeksekusi file .php, melayani file statis (file_server), dan menangani try_files (mencari index.php untuk request direktori). Ini setara dengan blok server{} Nginx yang lengkap dengan try_files $uri $uri/ /index.php.
Mode worker mengubah segalanya: aplikasi di-bootstrap sekali saat worker dimulai, lalu melayani banyak request dari memori. Bootstrap — membaca autoload composer, meregistrasi service, koneksi database — tidak diulang.
Ada tiga cara mengaktifkan worker, tergantung setup kalian.
worker di php_serverlocalhost {
root * public/
php_server {
worker index.php 4
}
}Argumen kedua (4) adalah jumlah worker — padanan worker_num. Jika dihilangkan, defaultnya 2x jumlah core CPU. Lokasi file worker relatif terhadap root.
Untuk kontrol lebih detail, gunakan bentuk blok:
{
frankenphp {
worker {
file /app/public/index.php
num 4
env APP_ENV production
watch /app/**/*.php
}
}
}num — jumlah worker (default 2x core).env — environment variable khusus worker.watch — restart otomatis saat file berubah (berguna untuk development).max_consecutive_failures — batas gagal beruntun sebelum worker dianggap unhealthy (default 6).FRANKENPHP_CONFIGDi image Docker, kalian tidak menulis Caddyfile penuh — cukup inject konfigurasi via env var:
docker run \
-e FRANKENPHP_CONFIG="worker /app/public/index.php 4" \
-v $PWD:/app \
-p 80:80 -p 443:443 -p 443:443/udp \
dunglas/frankenphpArgumen terakhir (4) lagi-lagi adalah jumlah worker. Atau lewat Dockerfile:
FROM dunglas/frankenphp
ENV FRANKENPHP_CONFIG="worker ./public/index.php"
COPY . /appphp-server --workerUntuk development cepat tanpa Caddyfile:
frankenphp php-server --worker public/index.phpBahkan bisa ditambah --watch untuk restart otomatis:
frankenphp php-server --worker public/index.php --watch="/app/**/*.php"Tip
Semua jalur worker bermuara pada hal yang sama: FrankenPHP menjalankan skrip worker sebagai proses persisten dan menyisipkan panggilan frankenphp_handle_request() untuk setiap request. Kita bedah skrip worker itu sendiri di episode 5.
| Aspek | Classic (php_server polos) | Worker (worker index.php) |
|---|---|---|
| Bootstrap aplikasi | Per request | Sekali saat start |
| Perintah eksekusi | frankenphp run + Caddyfile | Sama, dengan subdirective worker |
| Konfigurasi tambahan | Tidak ada | worker_num, env, watch |
| Kompatibilitas kode | Semua kode | Kode yang bebas state leak |
| Performa | Setara PHP-FPM | Hingga puluhan kali lebih cepat |
| Risiko | Rendah | State persisten antar request |
Contoh nyata: aplikasi Laravel classic butuh ~50–100ms untuk cold start per request. Di mode worker, bootstrap 100ms itu dibayar sekali, lalu setiap request hanya membayar waktu pemrosesan aktual — sering kali di bawah 10ms.
root pada php_server; gunakan path absolut untuk menghindari ambiguitas.frankenphp_handle_request(). Untuk framework modern, pakai integrasi resminya (Laravel Octane di episode 6, Symfony runtime di episode 7) — jangan menulis loop manual tanpa alasan.memory_limit bisa menghabiskan RAM (ingat aturan episode 2).static $count di dalam fungsi bertahan antar request. Kode seperti ini akan memberikan perilaku yang tidak terduga.Pada episode 4 ini, kalian telah memahami dua mode eksekusi FrankenPHP dan cara mengaktifkannya.
Inti yang harus dibawa pulang:
php_server polos) = drop-in replacement PHP-FPM; aman untuk semua kode.worker, env var FRANKENPHP_CONFIG, atau flag --worker.worker_num) default 2x core; atur sesuai memori dan beban.watch memungkinkan hot restart untuk development.Di episode 5 selanjutnya kita membedah Worker Mode lebih dalam: boot & request handling — menulis skrip worker manual dengan frankenphp_handle_request() dan frankenphp_foreach_request(), perilaku superglobal antar request, restart worker, dan manajemen crash. Sampai jumpa di episode 5!