
Zastanawiasz się, „kiedy właściwie warto założyć trait?”, jakie są jego zalety, a jakie wady? A może po prostu nie wiesz, czym jest trait w PHP, w takim razie zapraszam do artykułu, który napisałem na ten temat.
U mnie te nieliczne razy, kiedy zakładałem trait, wiązały się z pisaniem widżetów dla Elementora albo PrestaShopa. Weźmy widżet Elementora: on już dziedziczy po pewnej klasie, a ja nie mam ochoty budować klasy dziedziczącej po kolejnej i po jeszcze jednej tylko po to, żeby współdzielić dwie czy trzy metody. I tu wchodzi trait, który pozwala te metody wyciągnąć do wspólnego miejsca. W uproszczeniu trait sprowadza się do kopiuj-wklej.
trait CarouselTrait
{
public function getScriptDepends()
{
return ['swiper'];
}
protected function registerCarouselSection(array $args = [])
{
// Reszta kodu, który wyświetla opcje
// konfiguracyjne w Elementorze
}
}
Zalety traitów w PHP
-
Jeśli chcesz współdzielić kod między kilkoma klasami, trait jest alternatywą dla rozszerzania klasy. Bywa opcją lepszą, bo nie należy do hierarchii typów: klasa, która używa traitu, nie jest „instancją tego traitu”.
-
Trait oszczędza ci ręcznego kopiuj-wklej, bo robi kopiuj-wklej na etapie kompilacji.
Wady traitów w PHP
Z drugiej strony traity przynoszą kilka problemów. Na przykład:
-
Kiedy trait dokłada klasie jedną albo kilka metod publicznych, zwykle chciałoby się opisać te metody interfejsem, który klasa implementowałaby automatycznie przez samo użycie traitu. To niemożliwe. Trait nie może implementować interfejsu. Jeśli chcesz taki efekt, musisz użyć traitu i zaimplementować interfejs jawnie.
-
Traity nie mają własnych metod i właściwości „prywatnych”. Często chciałbym ukryć pewne rzeczy przed klasą, w której trait jest używany, ale nie da się zrobić niczego naprawdę „prywatnego”. Wszystko, co w traicie oznaczysz jako private, i tak pozostanie dostępne dla klasy, która ten trait wciąga. Trait nie jest więc w stanie niczego enkapsulować.
Alternatywy dla traitów w PHP
Tak czy inaczej w praktyce zawsze znajdzie się alternatywa dla traitu. Oto kilka przykładów:
-
Jeśli trait pełni obowiązki serwisu, lepiej zamienić go w prawdziwy serwis, który można, i należy, wstrzyknąć jako argument konstruktora do serwisu, który go potrzebuje. To właśnie nazywa się komponowaniem zachowania (composing behavior) w opozycji do dziedziczenia zachowania. To samo podejście sprawdza się, gdy chcesz pozbyć się klas nadrzędnych.
-
Jeśli trait dokłada encji zachowanie, które jest identyczne dla innej encji, często rozsądniej wprowadzić value object w PHP i użyć go zamiast traitu.
Podsumowanie
Trait jest dla mnie rozwiązaniem na skróty, to raczej sposób na uporządkowanie kodu niż cokolwiek innego, zamiast dublowania linii albo wkładania dziedziczenia jedno w drugie.


