Mechanizm Traits(cechy) w PHP został dodany w wersji 5.4 i nie występuje w innych językach programowania. Traitsy zostały zaprojektowane by umożliwić programiście użycie kodu w różnych klasach przez pominięcie ograniczeń jednokrotnego dziedziczenia klas(klasa w PHP może dziedziczyć wyłączznie z jednej klasy).

Trait jest podobna do klasy z tym wyjątkiem, że nie może zostać zainicjowana jako obiekt.

Przykład Trait:

trait Logger
{
     public function setLogger()
     {
          //set logger
     }
    
     public function getLogs()
     {
         //get logs
     }
}

class ClassThatUseLogger
{
     use Logger;
}

$logger = new ClassThatUseLogger();
$logger->setLogger();
$logger->getLogs();

Traity mogą używać metod z innych traitów, wystarczy użyć słowa kluczowego use, ponadto mogą posiadać metody abstrakcyjne i użycie takiego Traita wymusza na programiście zaimplementowanie tej metody w klasie, gdzie trait został użyty.

Trait może również posiadać metody statyczne i właściwości. Jeśli metoda w Trait jest typu public możemy ją zapisać w klasie jako private lub protected używając słowa kluczowego as

trait Logger
{
     public function setLogger()
     {
          //set logger
     }
    
     public function getLogs()
     {
         //get logs
     }
}

class ClassThatUseLogger
{
     use Logger { getLogs as protected; } 
}

$logger = new ClassThatUseLogger();
$logger->setLogger();

lub nawet zmienić nazwę metody używając lini

use Logger { getLogs as protected getLoggerFancy; }

W przypadku zmiennych statycznych każda klasa posiadająca cechę(Trait) będzie miała osobną zmienną typu static. Jest to innych mechanizm niż w przypadku dziedziczenia gdzie zmienna jest wspólna dla każdego obiektu klasy.

Na koniec pokaże praktyczny przykład wykorzystania Traits w PHP na podstawie implementacji wzorca Singleton.

trait Singleton
{
   protected static $instance;
   
   final public static function getInstance()
   {
       return isset(static::$instance) ? static::$instance : static::$instance = new static;
   }

   final private function __construct(){ }
   final private function __clone(){ }
   final private function __wakeup(){ }
}


class Tester
{ 
   use Singleton;

   private $test = 0;

   public function add()
   { 
       $this->test++;
   } 
   public function show()
   {
         echo $this->test."\n";
   }
}

$tester = Tester::getInstance();
$tester->add();

$testerABC = Tester::getInstance();
$testerABC->show();
$testerABC->add();
$testerABC->show();
$testerABC->add();

Tester::getInstance()->show();

Wynikiem działania powyższego kodu będzie pojawienie się liczb 1,2,3. Działający kod możecie zobaczyć tutaj