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.