OOP II: Inheritance, Abstract, Interface & Trait
Pewarisan, method override, class abstrak, interface, trait, polimorfisme, dan kapan memakai komposisi.
Inheritance (pewarisan)
Class anak dapat mewarisi properti & method class induk memakai extends, lalu menambah atau mengganti (override) perilaku.
class Hewan
{
public function __construct(protected string $nama) {}
public function suara(): string
{
return '...';
}
public function perkenalan(): string
{
return "{$this->nama} berkata {$this->suara()}";
}
}
class Kucing extends Hewan
{
public function suara(): string
{
return 'meong';
}
}
echo (new Kucing('Mimi'))->perkenalan(); // Mimi berkata meong
parent::suara() memanggil versi induk. Tandai final pada class/method yang tidak boleh diturunkan atau di-override. PHP 8.3 menambah atribut #[\Override] agar PHP memeriksa bahwa method memang menimpa method induk (menangkap salah ketik nama).
Class abstrak
abstract class Bentuk
{
abstract public function luas(): float; // wajib diimplementasikan anak
public function deskripsi(): string
{
return sprintf('%s dengan luas %.2f', static::class, $this->luas());
}
}
Class abstrak tidak bisa di-new langsung; ia adalah kerangka setengah jadi untuk turunannya.
Interface — kontrak
interface BisaTerbang { public function terbang(): string; }
interface BisaBerenang { public function renang(): string; }
class Bebek extends Hewan implements BisaTerbang, BisaBerenang
{
public function terbang(): string { return 'mengepak'; }
public function renang(): string { return 'berenang'; }
}
Interface hanya mendeklarasikan apa yang bisa dilakukan, bukan bagaimana. Satu class boleh mengimplementasikan banyak interface (tetapi mewarisi satu class saja). Interface membuat kode longgar terikat: fungsi yang menerima PembayaranInterface bisa bekerja dengan Transfer, Kartu, atau QRIS tanpa tahu detailnya.
Polimorfisme
interface Pembayaran { public function bayar(int $jumlah): string; }
class Transfer implements Pembayaran { public function bayar(int $jumlah): string { return "Transfer Rp{$jumlah}"; } }
class Qris implements Pembayaran { public function bayar(int $jumlah): string { return "QRIS Rp{$jumlah}"; } }
function checkout(Pembayaran $metode, int $total): string
{
return $metode->bayar($total); // tidak peduli kelas konkretnya
}
Trait — berbagi kode horizontal
trait MencatatWaktu
{
public ?string $dibuatPada = null;
public function tandaiDibuat(): void
{
$this->dibuatPada = date('c');
}
}
class Artikel { use MencatatWaktu; }
class Komentar { use MencatatWaktu; }
Trait menyalin method ke dalam class yang memakainya — berguna untuk perilaku yang dipakai banyak class tanpa hubungan pewarisan (timestamp, logging). Jangan berlebihan; trait yang besar membuat alur sulit dilacak.
Komposisi lebih baik dari pewarisan
Pewarisan yang dalam membuat kode kaku. Aturan praktis: pakai extends untuk hubungan "adalah" yang sungguh-sungguh (Kucing adalah Hewan); untuk hubungan "memiliki / memakai", suntikkan objek lain lewat constructor (dependency injection):
class PesananService
{
public function __construct(private Pembayaran $metode) {}
public function proses(int $total): string
{
return $this->metode->bayar($total);
}
}
Prinsip SOLID singkat
- S — satu class, satu tanggung jawab
- O — terbuka untuk ditambah, tertutup untuk diubah
- L — turunan harus bisa menggantikan induk
- I — interface kecil dan fokus
- D — bergantung pada abstraksi (interface), bukan class konkret