Introdotti in PHP 5.4 ma ignorati per anni, i Trait sono un costrutto molto utile perché ci aiuteranno ad estendere le funzionalità di una classe, come per l’ereditarietà, ma senza tutte le implicazioni connesse a questa tecnica. Un Trait consiste in una serie di metodi e proprietà che possono essere utilizzati da una classe.
Il miglior modo per capire i Trait è considerarli come una sorta di copia e incolla assistito che PHP ci mette a disposizione.
Quando definiremo un Trait lo faremo proprio come se fosse una classe, implementando metodi e proprietà. Una classe potrà poi utilizzare questo e più Trait contemporaneamente per includere automaticamente il loro codice.
<?php trait Poligono { public $x; function quadrato() { echo "Disegno un quadrato!"; } function rettangolo() { echo "Disegno un rettangolo!"; } }
Vediamo che la definizione di un Trait è identica a quella di una comune Classe, tranne che per la keyword trait. Per far sì che una classe possa sfruttare i metodi quadrato() e poligono() e la proprietà $x utilizziamo, all’interno della Classe, la keyword use seguita dal nome del Trait. Piccolo consiglio: è buona regola definire un solo Trait per file.
<?php class Disegno { use Poligono; } $test = new Disegno; $test->rettangolo(); // Disegno un rettangolo!
Una volta che nella classe Disegno abbiamo deciso di utilizzare il Trait Poligono, i suoi metodi (e proprietà) saranno disponibili direttamente, proprio come se li avessimo copiati e incollati. Non possiamo quindi modificarli direttamente.
Una regola fondamentale che dobbiamo tenere presente è che se la Classe ha già un metodo o una proprietà con lo stesso nome che il Trait utilizza, il membro del Trait avrà la precedenza.
Sarà anche possibile utilizzare più Trait allo stesso tempo separando i nomi dei Trait con una virgola:
<?php class Disegno { use Poligono, Cerchio; }
Ok, ma cosa succede se entrambi questi Trait hanno, ipotizziamo, un metodo chiamato annullaTutto()? PHP genererà un fatal error. Vediamo quindi come dire a PHP di utilizzare il metodo di un Trait anziché l’altro tramite la keyword insteadof:
<?php trait Poligono { function annullaTutto() { echo "Annullo il Poligono"; } } trait Cerchio { function annullaTutto() { echo "Annullo il Cerchio"; } } class Disegno { use Poligono, Cerchio { Poligono::annullaTutto insteadof Cerchio; } } $test = new Disegno; $test->annullaTutto(); // Annullo il Poligono
Abbiamo detto, quindi, alla classe Disegno di utilizzare il metodo annullaTutto() che abbiamo ottenuto dal trait Poligono anziché quello del trait Cerchio.