Sejak PHP 8.0 dirilis pada akhir 2020, PHP beralih ke siklus rilis tahunan: satu versi utama baru tiap akhir tahun, dengan masa dukungan bugfix dua tahun dan masa dukungan keamanan dua tahun berikutnya. Chapter-chapter sebelumnya pada section ini telah membedah fitur-fitur besarnya satu per satu, mulai dari named arguments hingga property hooks. Kali ini kita menarik diri sedikit ke belakang untuk melihat peta keseluruhan: fitur apa yang datang di tiap versi dan masalah lama apa yang diselesaikannya. Peta semacam ini berguna ketika Anda membaca kode warisan (legacy code), menimbang upgrade, atau memutuskan fitur mana yang aman dipakai di proyek Anda. Seluruh contoh pada chapter ini diuji pada PHP 8.4, sehingga setiap fitur dari 8.0 sampai 8.4 dapat dijalankan langsung.

Peta Fitur per Versi #

Tabel berikut merangkum fitur andalan tiap versi beserta masalah lama yang dijawabnya. Gunakan tabel ini sebagai indeks cepat — setiap fitur yang disebut memiliki chapter khusus di section ini bila ingin diperdalam.

VersiFitur AndalanMasalah Lama yang Dijawab
8.0Named arguments, match, nullsafe ?->, union types, constructor property promotion, JITUrutan argumen yang kaku, switch yang bertele-tele, pengecekan null berantai, nilai kembali tanpa batasan tipe
8.1Enums, readonly property, first-class callable, intersection types, never, fibersKonstanta class sebagai “enum palsu”, property yang bisa diubah diam-diam, Closure::fromCallable() yang panjang
8.2Readonly class, tipe true/false/null berdiri sendiri, DNF typesKata kunci readonly yang diulang di tiap property, tipe bool yang terlalu luas untuk kasus yang pasti
8.3json_validate(), atribut #[\Override], typed class constantsjson_decode() yang boros hanya untuk mengecek validitas, kekeliruan nama method saat override tidak terdeteksi
8.4Property hooks, asymmetric visibility, new tanpa kurung, mb_trim(), array_find()/array_any()/array_all(), lazy objectsGetter/setter boilerplate, visibilitas baca dan tulis yang terpaksa seragam, trim() yang buta terhadap Unicode

PHP 8.0 — Fondasi Bahasa Modern #

PHP 8.0 adalah lompatan terbesar dalam satu dekade karena mengubah sintaks harian sekaligus fondasi engine. Named arguments membebaskan pemanggil dari hafalan urutan parameter, match mengembalikan nilai tanpa perlu break, dan nullsafe operator ?-> memotong rangkaian if pengecekan null. Union types membuka jalan menuju type system yang kaya — pokok bahasan Section berikutnya. Sementara itu, JIT (Just In Time compiler) mempercepat beban kerja numerik yang berat; efeknya dirasakan pada performa, bukan pada output program.

php
<?php
// Named arguments: urutan bebas, arti argumen jelas
function buatKopi(string $jenis, int $gula = 1, bool $panas = true): string
{
    return $gula . " sachet gula, kopi " . $jenis . ($panas ? " panas" : " dingin");
}

echo buatKopi(gula: 2, jenis: "Gayo") . "\n";

// Match: cabang berbasis nilai yang langsung mengembalikan nilai
$kode = 200;
echo match (true) {
    $kode >= 200 && $kode < 300 => "sukses",
    $kode >= 400 => "galat klien",
    default => "tidak dikenal",
} . "\n";

// Nullsafe: menelusuri null tanpa if bertingkat
$pengguna = null;
echo ($pengguna?->alamat?->kota) ?? "alamat kosong" . "\n";

// Union types: satu deklarasi untuk beberapa kemungkinan tipe
function totalBelanja(int|float ...$item): int|float
{
    return array_sum($item);
}

echo totalBelanja(10000, 2.5) . "\n";

Output yang Dihasilkan:

text
2 sachet gula, kopi Gayo panas
sukses
alamat kosong
10002.5

Empat fitur bekerja bersama dalam satu berkas tersebut:

  1. Named arguments — pemanggilan buatKopi(gula: 2, jenis: "Gayo") melompati parameter $panas tanpa harus mengisi true secara eksplisit; setiap argumen menyebut namanya sendiri sehingga urutan bebas.
  2. match — ekspresi match (true) mengevaluasi tiap arm dari atas; arm pertama yang bernilai benar menang, tanpa break dan tanpa risiko fall-through seperti pada switch.
  3. Nullsafe — $pengguna?->alamat?->kota berhenti aman menghasilkan null begitu salah satu ruas bernilai null; operator ?? kemudian menyediakan nilai cadangan.
  4. Union types — int|float pada parameter variadic maupun return type menyatakan bahwa kedua jenis angka sama-sama diterima.

Bedah tuntas tiap fitur tersedia di chapter Named Arguments , Match Expressions , Nullsafe Operator , dan Union Types .

PHP 8.1 — Enum, Readonly, dan First-Class Callable #

PHP 8.1 menyumbang dua fitur struktural yang paling sering dipakai kode modern: enum untuk himpunan nilai tetap dan readonly property untuk nilai yang terkunci setelah konstruksi. First-class callable syntax strlen(...) menggantikan Closure::fromCallable('strlen') yang panjang. Intersection types mempertajam union types dengan menyaratkan sebuah nilai memenuhi beberapa tipe sekaligus, return type never menandai fungsi yang tidak pernah kembali, dan fibers memberi blok bangunan eksekusi kooperatif bagi pustaka kode asinkron.

php
<?php
enum StatusPesanan: string
{
    case Baru = "baru";
    case Diproses = "diproses";
    case Selesai = "selesai";
}

$label = match (StatusPesanan::Diproses) {
    StatusPesanan::Baru => "pesanan baru masuk",
    StatusPesanan::Diproses => "pesanan sedang dikemas",
    StatusPesanan::Selesai => "pesanan sudah dikirim",
};
echo $label . "\n";

class Harga
{
    public function __construct(public readonly int $jumlah) {}
}

echo (new Harga(15000))->jumlah . "\n";

$panjang = strlen(...);
echo $panjang("PHP modern") . "\n";

Output yang Dihasilkan:

text
pesanan sedang dikemas
15000
10

Mari kita bedah contoh tersebut:

  1. Enum — StatusPesanan mendefinisikan tiga kemungkinan status sebagai case dengan backing value string; match pada objek enum (tanpa ->value) membandingkan identitas case, bukan teks stringnya. Karena seluruh case terdaftar, tidak ada jalur status yang terlewat.
  2. readonly property + promotion — public readonly int $jumlah digabung dengan constructor property promotion (fitur 8.0): parameter constructor sekaligus menjadi property terkunci yang tidak bisa ditulis ulang.
  3. First-class callable — strlen(...) membungkus fungsi global menjadi Closure tanpa perlu string nama fungsi; hasilnya lalu dipanggil seperti fungsi biasa.

Pembahasan mendalam ada di chapter Enums , Readonly Properties dan Classes , Intersection Types , Never Return Type , dan Fibers .

PHP 8.2 — Readonly Class dan Tipe Baru #

PHP 8.2 menyempurnakan dua fitur pendahulunya. Kata kunci readonly kini dapat menempel pada class sehingga seluruh property terkunci sekaligus — tidak perlu mengulang readonly di tiap property. Tipe true, false, dan null kini boleh berdiri sendiri, sehingga fungsi yang pasti mengembalikan true saat sukses dapat menyatakannya secara jujur. DNF types melengkapi keduanya dengan mengizinkan gabungan intersection dan union dalam satu deklarasi, misalnya (Countable&Iterator)|null.

php
<?php
readonly class Kredensial
{
    public function __construct(
        public string $pengguna,
        public string $token,
    ) {}
}

$kredensial = new Kredensial("budi", "YOUR_API_TOKEN");
echo $kredensial->pengguna . "\n";

function koneksiSiap(): true
{
    return true;
}

var_dump(koneksiSiap());

Output yang Dihasilkan:

text
budi
bool(true)

Tiga hal terjadi pada contoh di atas:

  1. readonly class — satu kata kunci readonly di depan class membuat kedua property promoted di dalamnya terkunci; penugasan ulang seperti $kredensial->token = "x" setelah konstruksi memicu Error.
  2. Tipe true — return type true menyatakan bahwa satu-satunya nilai yang mungkin dikembalikan adalah true; fungsi pengece keberhasilan menjadi jujur secara tipe. Tipe false dan null berdiri sendiri dengan cara yang sama.
  3. Placeholder kredensial — nilai YOUR_API_TOKEN sengaja berupa penampung; jangan pernah menaruh token nyata di dalam kode.

PHP 8.3 — Validasi JSON dan Atribut Override #

PHP 8.3 berfokus pada ketelitian. Fungsi json_validate() menjawab kebutuhan yang sangat umum: memeriksa validitas JSON tanpa harus mendekode seluruh dokumen. Atribut #[\Override] membuat niat menimpa method parent menjadi eksplisit — jika ternyata tidak ada method yang ditimpa, PHP menolak sejak deklarasi class, sehingga kekeliruan nama akibat refactor langsung ketahuan. Typed class constants menutup celah terakhir pada sistem tipe: konstanta kini punya type declaration layaknya property.

php
<?php
class Pemformat
{
    const string PEMISAH = "-";

    public static function gabung(string ...$bagian): string
    {
        return implode(self::PEMISAH, $bagian);
    }
}

echo Pemformat::gabung("PHP", "8", "3") . "\n";

var_dump(json_validate('{"versi": "8.3"}'));
var_dump(json_validate('{versi: 8.3}'));

class PemformatLoud extends Pemformat
{
    #[\Override]
    public static function gabung(string ...$bagian): string
    {
        return strtoupper(parent::gabung(...$bagian));
    }
}

echo PemformatLoud::gabung("php", "8", "3") . "\n";

Output yang Dihasilkan:

text
PHP-8-3
bool(true)
bool(false)
PHP-8-3

Mari kita bedah fitur-fiturnya:

  1. Typed class constant — const string PEMISAH memaksa konstanta berjenis string; penugasan dengan tipe lain akan gagal, dan editor pun bisa mengandalkan tipe tersebut.
  2. json_validate() — mengembalikan bool tanpa membangun struktur data apa pun; teks {versi: 8.3} memang bukan JSON valid karena kunci tidak berada dalam tanda kutip.
  3. #[\Override] — menegaskan bahwa PemformatLoud::gabung() sengaja menimpa method parent; bila nama method parent suatu saat berubah atau salah ketik, PHP menolak class dengan fatal error sejak awal.

PHP 8.4 — Property Hooks dan Ergonomi Baru #

PHP 8.4 menyapu bersih boilerplate yang tersisa. Property hooks memindahkan logika getter/setter langsung ke property, sementara asymmetric visibility memisahkan hak baca dan hak tulis — misalnya baca public tetapi tulis private. Kata kunci new pada nilai default parameter tidak lagi memerlukan tanda kurung, keluarga mb_trim() menghadirkan pemangkasan teks yang sadar Unicode, dan array_find()/array_any()/array_all() mengisi celah lama pada operasi array. Lazy objects menutup daftar sebagai fondasi inisialisasi objek yang ditunda.

php
<?php
class NamaProduk
{
    public string $nilai {
        set (string $nilai) {
            $this->nilai = trim($nilai);
        }
    }

    public function __construct(string $nilai)
    {
        $this->nilai = $nilai;
    }
}

$produk = new NamaProduk("  Kopi Toraja  ");
echo "[" . $produk->nilai . "]\n";

$stok = [
    ["nama" => "Kopi Gayo", "sisa" => 0],
    ["nama" => "Teh Melati", "sisa" => 12],
];

$tersedia = array_find($stok, fn(array $item): bool => $item["sisa"] > 0);
echo "Tersedia: " . $tersedia["nama"] . "\n";

var_dump(array_any($stok, fn(array $item): bool => $item["sisa"] === 0));
var_dump(array_all($stok, fn(array $item): bool => $item["sisa"] > 0));

$label = "\u{00A0}Kopi Gayo\u{00A0}";
var_dump(trim($label) === "Kopi Gayo");
var_dump(mb_trim($label) === "Kopi Gayo");

Output yang Dihasilkan:

text
[Kopi Toraja]
Tersedia: Teh Melati
bool(true)
bool(false)
bool(false)
bool(true)

Perhatikan empat fitur pada contoh tersebut:

  1. Property hook — setiap penugasan ke $produk->nilai melewati hook set yang memangkas spasi; akses baca tetap terlihat seperti property biasa dari luar class.
  2. array_find() — mengembalikan elemen pertama yang lolos callback (bukan boolean), atau null bila tidak ada yang lolos.
  3. array_any() dan array_all() — menjawab pertanyaan “ada sekurang-kurangnya satu yang lolos” dan “semua lolos” dalam satu panggilan, tanpa loop manual.
  4. mb_trim() — NBSP (\u{00A0}, non-breaking space) bukan spasi ASCII sehingga trim() membiarkannya menempel; mb_trim() mengenalinya sebagai whitespace Unicode dan membuangnya.

Ergonomi kecil juga ikut menumpuk. Sejak PHP 8.4, new pada nilai default parameter boleh ditulis tanpa tanda kurung:

php
<?php
class Penanda
{
    public function label(): string
    {
        return "penanda";
    }
}

// PHP 8.4: "new" tanpa tanda kurung pada nilai default parameter
function ambilLabel(Penanda $penanda = new Penanda): string
{
    return $penanda->label();
}

echo ambilLabel() . "\n";

Output yang Dihasilkan:

text
penanda

Nilai default $penanda = new Penanda membangun objek segar setiap kali argumen tidak diisi — sebelum PHP 8.4, penulisan seperti ini wajib memakai tanda kurung new Penanda(). Bedah lengkap fitur visualisasi tingkat lanjutnya ada di chapter Property Hooks dan Asymmetric Visibility .

Referensi #

Ringkasan #

PHP 8.0 meletakkan fondasi sintaks modern lewat named arguments, match, nullsafe, dan union types; 8.1 membawa enum dan readonly; 8.2 merapikan keduanya sekaligus memperkaya jenis tipe; 8.3 menambah ketelitian lewat json_validate() dan #[\Override]; dan 8.4 menyapu boilerplate dengan property hooks serta koleksi fungsi baru. Dengan peta ini, Anda bisa membaca kode modern mana pun dan tahu fitur apa yang sedang dipakai beserta versi minimum yang diminta. Peta ini juga menimbulkan pertanyaan praktis: bagaimana jika server produksi Anda belum semuanya berjalan di 8.4? Chapter berikutnya menjawabnya dengan teknik menjaga kompatibilitas antar versi.