1. Class Modern dan Constructor Property Promotion (Sejak PHP 8.0)
Di PHP versi lama, membuat sebuah class sederhana dengan 4 properti mengharuskan kita menulis nama properti yang sama sebanyak empat kali (deklarasi properti, parameter konstruktor, penugasan $this->a = $a, dan getter).
Sejak PHP 8.0, fitur Constructor Property Promotion memungkinkan Anda mendeklarasikan visibilitas (public, protected, private) langsung di dalam parameter __construct(), dan PHP otomatis membuatkan properti sekaligus mengisi nilainya!
<?php
declare(strict_types=1);
class KursusKodeloka
{
public function __construct(
public string $slug,
public string $judul,
public int $jumlahModul,
private string $kodeInternal = 'KDLK-00',
) {}
public function infoRingkas(): string
{
return sprintf('%s (%d modul)', $this->judul, $this->jumlahModul);
}
}
$kursus = new KursusKodeloka('php', 'Pemrograman PHP Modern', 15);
echo $kursus->infoRingkas(); // "Pemrograman PHP Modern (15 modul)"
new MyClass()->method() Tanpa Kurung Tambahan!Sebelum PHP 8.4, jika Anda ingin langsung memanggil metode saat membuat objek baru, Anda wajib membungkus new dengan tanda kurung ekstra: (new KursusKodeloka(...))->infoRingkas(). Sejak PHP 8.4, Anda dapat langsung menulisnya dengan bersih tanpa kurung pembungkus: echo new KursusKodeloka('php', 'PHP Modern', 15)->infoRingkas();
2. Immutability dengan readonly Class dan clone() Baru (PHP 8.2 & 8.5)
Objek yang nilainya tidak dapat diubah lagi setelah dibuat (Immutable Value Object / Data Transfer Object) sangat aman karena Anda dapat meneruskannya ke fungsi mana pun tanpa khawatir datanya diubah secara diam-diam.
- Sejak PHP 8.1, Anda dapat menandai properti individual dengan kata kunci
readonly. - Sejak PHP 8.2, menandai seluruh class sebagai
readonly classotomatis menjadikan seluruh properti di dalamnya bersifatreadonly! - Dan sejak PHP 8.5, ketika Anda ingin membuat salinan dari objek
readonlysambil memperbarui satu propertinya saja (pola with-er), fungsiclone($objek, ['properti' => $nilaiBaru])kini mendukung pembaruan properti secara langsung saat penyalinan!
<?php
declare(strict_types=1);
readonly class KonfigurasiKoneksi
{
public function __construct(
public string $host,
public int $port = 5432,
public int $timeoutDetik = 5,
) {}
// Pola "with-er" untuk objek immutable:
// Sejak PHP 8.5, clone() menerima argumen ke-2 berupa array properti yang ingin diperbarui!
public function denganTimeout(int $detikBaru): self
{
return clone($this, [
'timeoutDetik' => $detikBaru,
]);
}
}
$koneksiUtama = new KonfigurasiKoneksi('db.kodeloka.internal');
// $koneksiUtama->timeoutDetik = 10; // Error! Properti readonly tidak boleh diubah di tempat.
$koneksiLaporan = $koneksiUtama->denganTimeout(30);
echo $koneksiUtama->timeoutDetik; // Tetap 5
echo $koneksiLaporan->timeoutDetik; // 30
3. Visibilitas Asimetris (public private(set)) dan Property Hooks (Sejak PHP 8.4)
Bagaimana jika sebuah objek bukan objek immutable (nilai di dalamnya masih boleh berubah melalui metode bisnis internal class), tetapi Anda ingin pihak luar bisa membaca nilainya secara langsung tanpa boleh mengubahnya dari luar?
Dulu kita harus membuat properti private lalu menulis metode getSaldo() yang bertele-tele. Sejak PHP 8.4, hadir dua fitur revolusioner:
A. Asymmetric Visibility (public private(set) — Sejak PHP 8.4)
Anda dapat mengatur hak baca (read) dan hak tulis (write/set) sebuah properti secara terpisah:
<?php
declare(strict_types=1);
class DompetBelajar
{
// Boleh DIBACA oleh siapa saja (public),
// tetapi HANYA boleh DIUBAH dari dalam class ini sendiri (private(set))!
public private(set) int $poin = 0;
public function tambahPoinSelesaiModul(int $tambahan = 10): void
{
if ($tambahan <= 0) {
throw new InvalidArgumentException('Poin harus positif.');
}
$this->poin += $tambahan;
}
}
$dompet = new DompetBelajar();
$dompet->tambahPoinSelesaiModul(25);
echo $dompet->poin; // 25 (Bisa dibaca langsung tanpa getPoin()!)
// $dompet->poin = 9999; // Error! Tidak boleh diubah dari luar class DompetBelajar.
B. Property Hooks (get dan set — Sejak PHP 8.4)
Property Hooks memungkinkan Anda menempelkan logika validasi/normalisasi saat properti diisi (set), atau membuat properti terhitung (virtual property dengan get), langsung pada deklarasi properti tanpa mengubah cara pemanggil mengakses $objek->properti:
<?php
declare(strict_types=1);
class Pengguna
{
// 1. Backed property dengan hook 'set' untuk menormalisasi dan memvalidasi surel
public string $surel {
set (string $nilai) {
$bersih = strtolower(trim($nilai));
if (!filter_var($bersih, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException("Format surel tidak sah: {$nilai}");
}
$this->surel = $bersih;
}
}
// 2. Virtual property (hanya punya hook 'get', tidak memakan memori penyimpanan tersendiri)
public string $namaLengkap {
get => trim("{$this->namaDepan} {$this->namaBelakang}");
}
public function __construct(
public string $namaDepan,
public string $namaBelakang,
string $surel,
) {
$this->surel = $surel; // Otomatis melewati hook 'set' di atas!
}
}
$user = new Pengguna('Nadia', 'Pratama', ' [email protected] ');
echo $user->surel; // "[email protected]"
echo $user->namaLengkap; // "Nadia Pratama"
4. Kontrak dengan interface, Pewarisan abstract class (#[\Override]), dan trait
interface(Kontrak Kemampuan): Mendefinisikan tanda tangan metode publik yang wajib diimplementasikan oleh sebuah class (class PengirimSmtp implements PengirimNotifikasi). Satu class dapat mengimplementasikan banyakinterface.abstract class&#[\Override](Sejak PHP 8.3): Ketika subkelas menimpa metode milik kelas induk atau mengimplementasikan metode interface, tambahkan atribut#[\Override]di atas metode tersebut! Dengan#[\Override], PHP akan segera memberi tahu Anda jika nama metode salah ketik atau jika kelas induk mengubah nama metodenya di masa depan.trait: Mekanisme penggunaan ulang kode secara horizontal (use MencatatWaktu;) ketika beberapa class yang tidak memiliki hubungan induk-anak membutuhkan metode pembantu yang sama.
Latihan Praktik: Merancang Entitas Produk dengan Asymmetric Visibility dan Property Hooks
Buatlah berkas entitas-produk.php:
- Buat
class Produkyang menggunakan constructor property promotion untukpublic readonly string $kodeSku. - Tambahkan properti
public private(set) int $stok = 0dan metodetambahStok(int $jumlah)sertakurangiStok(int $jumlah). - Tambahkan properti
$hargaRupiahdengan property hooksetyang menolak nilai negatif (InvalidArgumentException), serta virtual property$hargaTerformatdengan hookgetyang mengembalikan'Rp' . number_format($this->hargaRupiah, 0, ',', '.').