ooptraitMahir3 mnt baca

Trait

Pakai ulang kode antar class tanpa inheritance: trait sebagai potongan kemampuan.

Analogi: Skill yang Bisa Ditempel

Inheritance memberi warisan vertikal (orang tua ke anak), tapi bagaimana kalau banyak class tak berhubungan butuh kemampuan sama, misalnya logging? Menaruhnya di induk memaksa hierarki palsu. Trait seperti skill yang bisa ditempel: tulis sekali, pakai di class mana pun dengan use, tanpa hubungan keluarga.

php
<?php
// Contoh 1: trait untuk logging
trait BisaLog {
    public function log(string $pesan): void {
        file_put_contents("app.log",
            date("Y-m-d H:i:s") . " " . $pesan . "\n", FILE_APPEND);
    }
}

class Kasir {
    use BisaLog;   // tempel kemampuan logging

    public function bayar(float $jumlah): void {
        // ... proses ...
        $this->log("Bayar Rp$jumlah");   // method dari trait!
    }
}

class Gudang {
    use BisaLog;   // class tak berhubungan, skill sama

    public function tambahStok(string $barang): void {
        $this->log("Stok $barang ditambah");
    }
}

Kasir dan Gudang tidak berbagi induk, tapi keduanya "bisa log". Tanpa trait, kamu menduplikasi method log() di dua tempat atau membuat hierarki aneh.

php
<?php
// Contoh 2: banyak trait + aturan konflik
trait BisaCache {
    public function simpanCache(string $kunci, $nilai): void { /* ... */ }
}

trait BisaNotifikasi {
    public function kirim(string $pesan): void { /* ... */ }
}

class Produk {
    use BisaLog, BisaCache, BisaNotifikasi;   // tempel tiga skill sekaligus
}

// Jika dua trait punya method bernama sama:
trait A { public function sapa() { return "A"; } }
trait B { public function sapa() { return "B"; } }

class C {
    use A, B {
        A::sapa insteadof B;   // pilih versi A
        B::sapa as sapaB;     // versi B tetap bisa dipakai dengan nama alias
    }
}

Aturan konflik eksplisit (insteadof, as) memang terlihat ribet, tapi justru itu kelebihannya dibanding inheritance: konflik tidak pernah diam-diam, kamu dipaksa memilih.

Jebakan yang Sering Terjadi

Trait sebagai tempat sampah kode. Trait idealnya kohesif: satu kemampuan jelas (logging, caching, validasi). Trait "Helper" berisi 30 method tak berhubungan sama buruknya dengan class raksasa. Kalau trait butuh banyak property, itu tanda seharusnya jadi class.

Lupa trait bukan class. Trait tidak bisa di-new, tidak bisa punya konstanta (sampai PHP 8.2), dan tidak bisa extends. Ia hanya "bahan tempel". Jangan merancang trait seolah ia objek mandiri.

Trait vs Interface vs Inheritance

Ringkasan kapan memakai apa:

  • Inheritance (extends): hubungan "adalah" (Manajer adalah Pegawai). Satu induk saja.
  • Interface (implements): kontrak kemampuan ("bisa dibayar"). Banyak boleh.
  • Trait (use): tempelan implementasi ("punya kemampuan log"). Banyak boleh.
php
<?php
interface BisaDibayar { public function bayar(float $j): string; }

trait CatatLog {
    public function catat(string $m): void {
        file_put_contents("app.log", date("H:i") . " $m\n", FILE_APPEND);
    }
}

class Qris implements BisaDibayar {   // kontrak: wajib bisa dibayar
    use CatatLog;                    // tempelan: dapat kemampuan log gratis
    public function bayar(float $j): string {
        $this->catat("QRIS $j");
        return "QRIS lunas";
    }
}

Kombinasi ketiganya adalah arsitektur PHP modern: interface untuk kontrak, trait untuk kode reusable, inheritance seperlunya untuk hierarki nyata.

Catatan teknis: Method di class sendiri mengalahkan method trait bernama sama, dan method trait mengalahkan method warisan induk. Urutan prioritas: class sendiri > trait > induk. Hafalkan urutan ini saat debugging perilaku aneh.

Tantangan

Trait format rupiah

Buat trait FormatRupiah dengan method rupiah($angka) yang return format "Rp 1.500.000". Pakai trait ini di dua class tak berkerabat: Produk dan Transaksi. Tampilkan hasil dari keduanya.