Ketika kita menjalankan php hal.php, yang sesungguhnya bekerja adalah sebuah program utuh bernama runtime PHP: penerjemah yang membaca teks, memahaminya, lalu mengeksekusinya. Memahami runtime ini bukan ilmu tambahan yang bisa dilewati — diagnosa “halaman lambat”, keputusan mengaktifkan OPcache, hingga kebingungan “kenapa variabel saya hilang antar-request” semuanya dijawab oleh cara kerja runtime. Pada chapter ini kita membedah komponen-komponen runtime PHP, tahapan dari kode sumber sampai eksekusi, dan model per-request yang menjadi identitas PHP.
Komponen Utama PHP Runtime #
Runtime PHP terdiri dari tiga lapisan besar yang bekerja sama. Pertama, Zend Engine — inti bahasa yang bertanggung jawab mengurai sintaks, mengompilasi, dan mengeksekusi kode; namanya berasal dari pendirinya, Zeev Suraski dan Andi Gutmans, sejak era PHP 4. Kedua, extensions — modul-modul seperti pdo_sqlite untuk database atau curl untuk HTTP yang menambah kemampuan baru berupa fungsi dan class. Ketiga, SAPI (Server API) — lapisan antarmuka yang menentukan dari mana PHP dipanggil: lewat terminal (cli), lewat web server melalui PHP-FPM (fpm-fcgi), atau lewat server tertanam.
Ketiga lapisan ini menjelaskan satu fenomena yang sering membingungkan pemula: mengapa hasil php -v di terminal bisa berbeda perilaku dengan PHP yang menjalankan situs di hosting. Keduanya bisa jadi versi berbeda dengan set ekstensi berbeda dan php.ini berbeda — meskipun Zend Engine dan bahasanya sama. Sekumpulan konstanta bawaan memungkinkan kita mengintip identitas runtime dari dalam kode, seperti yang akan kita lakukan pada bagian penutup chapter ini.
Dari Kode Sumber ke Opcode #
Zend Engine memproses kode dalam beberapa tahap berurutan. Diagram berikut memetakan alurnya:
Berikut uraian setiap tahap pada diagram tersebut:
- Lexer memindai teks kode dan memotongnya menjadi token — pasangan jenis dan isi, misalnya variabel
$harga, angka15000, operator=. - Parser menyusun token menjadi AST (abstract syntax tree) — pohon yang menggambarkan struktur program, misalnya “penugasan ekspresi perkalian ke variabel”. Kesalahan sintaks terdeteksi di tahap ini, sebelum satu instruksi pun berjalan.
- Compiler menerjemahkan AST menjadi daftar opcode — instruksi mesin virtual tingkat rendah seperti “ambil nilai, kalikan, simpan”.
- Executor menjalankan opcode satu per satu sambil memelihara tabel variabel dan hasil antara; output dari
echodan teks HTML mengalir keluar pada tahap ini.
Tahap 1 sampai 3 inilah yang dikenal sebagai compile phase, dan proses ini berulang setiap kali berkas diminta — kecuali OPcache turun tangan. Ekstensi OPcache menyimpan opcode hasil kompilasi di memori bersama, sehingga permintaan berikutnya untuk berkas yang sama dapat langsung melompat ke tahap eksekusi tanpa mengulang lexing-parsing-compiling. Pada server produksi, OPcache praktis selalu diaktifkan karena penghematannya besar; pada PHP 8, mesin ini juga dilengkapi JIT (just-in-time compiler) opsional yang menerjemahkan opcode “panas” menjadi instruksi mesin asli untuk beban kerja tertentu.
Model Eksekusi Per-Request #
Karakter paling khas dari PHP adalah model shared-nothing per-request. Setiap permintaan HTTP menjalankan siklus hidup lengkap: runtime menyiapkan superglobal ($_GET, $_POST, $_SERVER, dan kawanannya) dari data permintaan, mengeksekusi skrip dari keadaan bersih, lalu setelah tanggapan terkirim seluruh keadaan — variabel, koneksi database, koneksi jaringan — dibongkar. Tidak ada memori bersama yang tersisa untuk permintaan berikutnya.
Model ini punya dua wajah. Wajah positifnya: penalaran menjadi sederhana dan isolasi kuat — memori bocor pada satu permintaan tidak menumpuk memengaruhi permintaan lain, dan Anda tidak perlu mengelola siklus hidup objek lintas permintaan. Konsekuensinya: keadaan yang perlu bertahan (data login pengguna, isi keranjang belanja) harus disimpan di luar memori proses, misalnya di session yang backend-nya berupa berkas atau database, dan koneksi database dibuka ulang per permintaan. Untuk kebutuhan proses long-running ala Node.js atau aplikasi realtime, komunitas PHP menyediakan jalur khusus seperti ekstensi Swoole dan runtime FrankenPHP — topik lanjutan di luar cakupan course dasar ini.
Mengintip Runtime dari Dalam #
PHP menyediakan konstanta dan fungsi untuk menanyakan identitas runtime yang sedang menjalankan kode kita. Program berikut memeriksa versi bahasa, SAPI yang dipakai, versi Zend Engine, hingga arsitektur integer:
<?php
echo "Versi PHP : " . PHP_VERSION . "\n";
echo "ID versi : " . PHP_VERSION_ID . "\n";
echo "SAPI aktif : " . PHP_SAPI . "\n";
echo "Zend Engine : " . zend_version() . "\n";
echo "Integer : " . PHP_INT_SIZE . " byte (" . (PHP_INT_SIZE * 8) . "-bit)\n";
echo "Sistem operasi : " . PHP_OS_FAMILY . "\n";Output yang Dihasilkan:
Versi PHP : 8.4.23
ID versi : 80423
SAPI aktif : cli
Zend Engine : 4.4.23
Integer : 8 byte (64-bit)
Sistem operasi : LinuxMari kita bedah tiap baris program di atas:
- Baris 2 dan 3:
PHP_VERSIONmenyajikan versi lengkap (misalnya8.4.23), sedangkanPHP_VERSION_IDmenyandikannya menjadi satu angka (misalnya80423) yang mudah dibandingkan — kita akan memanfaatkannya pada chapter Versi PHP dan Kompatibilitas. - Baris 4:
PHP_SAPImelaporkan antarmuka yang dipakai untuk memanggil PHP. Nilaicliberarti dari terminal; nilaifpm-fcgiatauapache2handlerberarti dari web server. - Baris 5: fungsi
zend_version()mengembalikan versi Zend Engine — angka yang mengikuti versi PHP. - Baris 6:
PHP_INT_SIZEadalah ukuran tipe integer dalam byte; angka ini menentukan apakah PHP berjalan 32-bit atau 64-bit. - Baris 7:
PHP_OS_FAMILYmerangkum keluarga sistem operasi sepertiLinux,Windows, atauDarwin(macOS).
Dari Zend Engine hingga SAPI, kita kini mengenal seluruh lapisan yang menghidupkan kode PHP. Satu aspek terakhir yang wajib dipahami sebelum menulis kode serius adalah versi: PHP berkembang setiap tahun, dan runtime yang menjalankan kode Anda hari ini mungkin bukan runtime yang sama milik rekan tim atau server produksi. Chapter berikutnya membahas peta versi PHP beserta cara menulis kode yang tetap kompatibel.