Mengapa Konstanta Biasa Tidak Cukup untuk Merepresentasikan Status?
Dalam aplikasi nyata, kita selalu berurusan dengan nilai-nilai yang pilihannya terbatas dan sudah pasti: status pesanan (menunggu, dibayar, dikirim, batal), peran pengguna (admin, instruktur, peserta), atau metode pembayaran.
Sebelum PHP 8.1, pengembang biasanya menggunakan konstanta kelas bertipe string:
// Cara Lama (Sebelum PHP 8.1):
class StatusPesananLama {
public const MENUNGGU = 'menunggu';
public const DIBAYAR = 'dibayar';
}
// Kelemahan: Parameter fungsi hanya bisa ditulis 'string $status',
// sehingga pemanggil tetap bisa mengirim 'ngawur' tanpa ditolak oleh tipe parameter!
Sejak PHP 8.1, Enumerations (enum) menyelesaikan masalah ini dengan menciptakan tipe data tersendiri yang anggotanya dibatasi secara ketat pada daftar case yang Anda tentukan!
1. Pure Enum (Enum Murni)
Pure Enum adalah Enum yang setiap anggotanya (case) berdiri sendiri sebagai instans objek singleton tanpa dikaitkan dengan nilai skalar string atau integer:
<?php
declare(strict_types=1);
enum TingkatKesulitan
{
case Dasar;
case Menengah;
case Lanjut;
}
function tampilkanLencana(TingkatKesulitan $tingkat): string
{
// Karena TingkatKesulitan hanya punya 3 case, ekspresi match ini
// sudah mencakup semua kemungkinan tanpa butuh cabang default!
return match ($tingkat) {
TingkatKesulitan::Dasar => '🟢 Dasar (Pemula)',
TingkatKesulitan::Menengah => '🟡 Menengah',
TingkatKesulitan::Lanjut => '🔴 Lanjut (Produksi)',
};
}
$pilihan = TingkatKesulitan::Dasar;
echo $pilihan->name; // Setiap Enum memiliki properti readonly ->name ("Dasar")
echo tampilkanLencana($pilihan);
Perhatikan bahwa setiap kasus Enum (TingkatKesulitan::Dasar) adalah objek singleton di memori, sehingga Anda dapat membandingkannya secara langsung dengan operator identitas ketat === ($pilihan === TingkatKesulitan::Dasar)!
2. Backed Enum (: string atau : int) untuk Database dan JSON
Ketika sebuah nilai Enum perlu disimpan ke dalam kolom tabel basis data PostgreSQL/MySQL, dikirim lewat formulir HTML <select>, atau diserialisasi ke dalam payload JSON API, gunakan Backed Enum dengan mendeklarasikan tipe skalar : string atau : int (hanya boleh salah satu, tidak boleh union int|string!):
<?php
declare(strict_types=1);
enum PeranPengguna: string
{
case Admin = 'admin';
case Instruktur = 'instruktur';
case Peserta = 'peserta';
}
// 1. Membaca nilai skalar untuk disimpan ke database melalui properti readonly ->value:
$peran = PeranPengguna::Instruktur;
echo $peran->name; // "Instruktur"
echo $peran->value; // "instruktur"
// 2. Mengambil seluruh daftar kasus yang tersedia dengan metode statis ::cases():
foreach (PeranPengguna::cases() as $kasus) {
echo "{$kasus->name} => {$kasus->value}\n";
}
Mengubah Nilai Database/Form Kembali Menjadi Enum: from() vs tryFrom()
Setiap Backed Enum secara otomatis dilengkapi dua metode pabrik statis bawaan:
PeranPengguna::from(string|int $nilai): Mengembalikan kasus Enum yang cocok, atau melemparValueErrorjika nilai tidak ditemukan. Gunakan untuk data dari sumber internal yang dijamin valid.PeranPengguna::tryFrom(string|int $nilai): Mengembalikan kasus Enum yang cocok, atau mengembalikannulljika nilai tidak ditemukan! Selalu gunakantryFrom()saat memproses input dari pengguna ($_POST,$_GET, JSON request)!
<?php declare(strict_types=1); $inputDariForm = $_POST['peran'] ?? ''; // Aman! Jika pengguna mengirim 'superhacker', tryFrom() mengembalikan null // sehingga otomatis jatuh ke nilai bawaan PeranPengguna::Peserta. $peranSah = PeranPengguna::tryFrom((string) $inputDariForm) ?? PeranPengguna::Peserta;
3. Menambahkan Metode, Konstanta, interface, dan JsonSerializable pada Enum
Di PHP, enum memiliki banyak kemampuan layaknya class (meskipun tidak boleh memiliki properti/state dinamis dan tidak boleh diwariskan dengan extends):
- Enum boleh memiliki metode publik/privat dan metode
static. - Enum boleh memiliki konstanta (
public const) dan memakaitrait(selama trait tidak berisi properti). - Enum boleh mengimplementasikan
interface(termasuk interface bawaanJsonSerializable). Catatan: Backed Enum sudah otomatis di-json_encode()menjadi nilai skalarnya tanpa interface ini, sedangkan Pure Enum akan menimbulkan galat;JsonSerializablehanya dipakai untuk mengubah perilaku bawaan tersebut (contoh di bawah menampilkannya secara eksplisit).
<?php
declare(strict_types=1);
interface MemilikiHakAkses
{
public function bolehMenulisMateri(): bool;
}
enum StatusPublikasi: string implements MemilikiHakAkses, JsonSerializable
{
case Draf = 'draf';
case Tinjauan = 'tinjauan';
case Terbit = 'terbit';
case Diarsipkan = 'arsip';
public const STATUS_BAWAAN = self::Draf;
public function bolehMenulisMateri(): bool
{
return match ($this) {
self::Draf, self::Tinjauan => true,
self::Terbit, self::Diarsipkan => false,
};
}
public function warnaLencana(): string
{
return match ($this) {
self::Draf => 'abu-abu',
self::Tinjauan => 'kuning',
self::Terbit => 'hijau',
self::Diarsipkan => 'merah',
};
}
public function jsonSerialize(): string
{
return $this->value;
}
}
echo json_encode(['status' => StatusPublikasi::Terbit]);
// Keluaran: {"status":"terbit"}
Latihan Praktik: Merancang Enum Metode Pembayaran Lengkap dengan Perhitungan Biaya
Buatlah berkas enum-pembayaran.php dan jalankan dengan php enum-pembayaran.php:
- Buat
enum MetodePembayaran: stringdengan kasusQris = 'qris',VirtualAccount = 'va', danKartuKredit = 'kartu'. - Tambahkan metode
hitungBiayaLayanan(int $nominalBelanja): intpada Enum tersebut menggunakan ekspresimatch ($this)(Qris=0.7%dari nominal,VirtualAccount= tetapRp4.000,KartuKredit=2.5%+Rp2.000). - Uji konversi input pengguna menggunakan
MetodePembayaran::tryFrom().