Trait PHP adalah blok method dan property yang bisa dipakai ulang. Kamu mendeklarasikannya dengan trait Name { ... } lalu menariknya ke class mana pun dengan use Name; di dalam badan class. PHP menyalin member trait ke dalam class, jadi semuanya bekerja persis seolah-olah kamu menulisnya langsung di sana.
User dan Robot tidak punya parent yang sama, tetapi sekarang keduanya punya hello(). Trait dibuat untuk kasus seperti ini: class PHP hanya bisa meng-extend satu class, dan trait membagikan kode secara menyamping, di antara class yang tidak saling berhubungan.
Trait dengan property
Trait bisa membawa property bersama method-nya. Method-nya memakai $this seperti method lain di class itu, karena begitu trait disalin ke dalam class, method-method itu menjadi method class tersebut:
Class tidak boleh mendeklarasikan property dengan nama yang sama dengan property trait, kecuali kedua deklarasinya identik (visibility, tipe, dan nilai default yang sama); kalau tidak, hasilnya fatal error.
Memakai beberapa trait
Tulis beberapa trait dalam satu pernyataan use, dipisahkan koma, atau tulis beberapa baris use. Class itu mendapat member dari semuanya:
Mengatasi bentrok dengan insteadof dan as
Kalau dua trait mendefinisikan method dengan nama yang sama, PHP menolak untuk menebak dan berhenti dengan fatal error. Di dalam blok use, insteadof memilih pemenangnya, dan as menyimpan method yang kalah dengan nama lain:
Dengan use EnglishGreeting, FrenchGreeting; biasa tanpa blok, script berhenti sebelum apa pun dicetak:
PHP Fatal error: Trait method FrenchGreeting::greet has not been applied as Host::greet, because of collision with EnglishGreeting::greet in /home/index.php on line 12
as juga bisa mengubah visibility. use Loggable { log as protected; } membuat log() milik trait itu menjadi protected hanya di class ini, dan use Loggable { log as private writeLog; } menambahkan alias private.
Member abstract dan static di trait
Trait bisa mewajibkan sesuatu dari class pemakainya dengan mendeklarasikan abstract method. Trait juga bisa punya static method dan static property. Setiap class yang memakai trait mendapat salinan static property-nya sendiri:
Car dan Bike menghitung secara terpisah, karena static property-nya disalin ke setiap class. Ini berbeda dengan static property yang dideklarasikan di parent class bersama, yang dipakai bersama oleh semua child-nya; halaman static menunjukkan kasus itu.
Method mana yang menang: class, trait, atau parent
Kalau nama method yang sama ada di class itu sendiri, di trait yang dipakainya, dan di parent class-nya, PHP memilih dengan urutan ini: method milik class itu sendiri, lalu milik trait, lalu milik parent. Di dalam trait, parent:: tetap bisa menjangkau versi milik parent:
Trait bukan sebuah tipe
instanceof tidak pernah cocok dengan trait, dan parameter yang bertipe nama trait menolak setiap objek dengan TypeError. Untuk menanyakan "apakah class ini punya perilaku tersebut", pasangkan trait dengan interface, atau periksa class-nya dengan class_uses():
Pola di atas adalah pola yang umum: interface Exportable adalah yang dipakai sebagai type hint oleh fungsi dan yang diperiksa oleh instanceof, dan trait ExportsProperties adalah implementasi siap pakai yang bisa dipakai atau diganti oleh class. Trait sendirian hanyalah kode bersama tanpa kontrak; kalau kamu mendapati dirimu memeriksa class_uses() di logika bisnis, trait itu sebenarnya butuh interface di sampingnya. Untuk kode yang dipakai bersama oleh sekelompok class yang saling berhubungan, abstract class mungkin pilihan yang lebih sederhana.
Pertanyaan yang sering diajukan
Apa itu trait di PHP?
Trait adalah kumpulan method (dan property) bernama yang dideklarasikan dengan trait Name { } dan ditarik ke dalam class dengan use Name;. PHP menyalin member trait ke dalam class, jadi semuanya berperilaku seolah-olah kamu menulisnya langsung di sana. Trait adalah cara untuk berbagi kode antar-class yang tidak punya parent yang sama.
Bisakah satu class PHP memakai beberapa trait?
Bisa: use Timestamps, SoftDeletes; atau beberapa baris use. Kalau dua trait mendefinisikan method dengan nama yang sama, kamu harus memilih salah satunya dengan insteadof, misalnya use A, B { A::hello insteadof B; }, dan kamu bisa menyimpan yang lain dengan nama baru lewat B::hello as helloB;.
Apa bedanya trait dan interface di PHP?
Interface adalah tipe tanpa kode: interface menyebutkan method apa saja yang wajib dimiliki sebuah class, dan instanceof bisa dipakai dengannya. Trait adalah kode tanpa tipe: trait menempelkan isi method ke dalam class, tetapi $obj instanceof SomeTrait selalu false. Keduanya sering dipakai bersama: interface untuk tipenya, trait untuk implementasi default-nya.
Bisakah trait punya constructor atau abstract method?
Bisa, keduanya. Trait bisa mendeklarasikan abstract public function name(): string; untuk mewajibkan class pemakainya menyediakan method itu, dan trait bisa mendefinisikan __construct, walaupun constructor di trait mudah bentrok dengan constructor milik class itu sendiri dan jarang menjadi ide yang baik.
Method mana yang menang kalau class dan trait mendefinisikan method yang sama?
Method milik class itu sendiri menang atas method trait, dan method trait menang atas method yang diwarisi dari parent class. Jadi urutannya: class, lalu trait, lalu parent.