Traits

Depuis PHP 5.4.0, PHP supporte une manière de réutiliser le code appelée Traits.

Les traits sont un mécanisme de réutilisation de code dans un langage à héritage simple tel que PHP. Un trait tente de réduire certaines limites de l'héritage simple, en autorisant le développeur à réutiliser un certain nombre de méthodes dans des classes indépendantes. La sémantique entre les classes et les traits réduit la complexité et évite les problèmes typiques de l'héritage multiple et des Mixins.

Un trait est semblable à une classe, mais il ne sert qu'à grouper des fonctionnalités d'une manière intéressante. Il n'est pas possible d'instancier un Trait en lui-même. C'est un ajout à l'héritage traditionnel, qui autorise la composition horizontale de comportements, c'est à dire l'utilisation de méthodes de classe sans besoin d'héritage.

Exemple #1 Exemple d'utilisation de Trait

<?php
trait ezcReflectionReturnInfo {
    function 
getReturnType() { /*1*/ }
    function 
getReturnDescription() { /*2*/ }
}

class 
ezcReflectionMethod extends ReflectionMethod {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}

class 
ezcReflectionFunction extends ReflectionFunction {
    use 
ezcReflectionReturnInfo;
    
/* ... */
}
?>

Précédence

Une méthode héritée depuis une classe mère est écrasée par une méthode issue d'un Trait. L'ordre de précédence fait en sorte que les méthodes de la classe courante écrasent les méthodes issues d'un Trait, elles-mêmes surchargeant les méthodes héritées.

Exemple #2 Exemple avec l'ordre de précédence

Une méthode héritée depuis la classe de base est écrasée par celle provenant du Trait. Ce n'est pas le cas des méthodes réelles, écrites dans la classe de base.

<?php
class Base {
    public function 
sayHello() {
        echo 
'Hello ';
    }
}

trait 
SayWorld {
    public function 
sayHello() {
        
parent::sayHello();
        echo 
'World!';
    }
}

class 
MyHelloWorld extends Base {
    use 
SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

L'exemple ci-dessus va afficher :

Hello World!

Exemple #3 Autre exemple d'ordre de précédence

<?php
trait HelloWorld {
    public function 
sayHello() {
        echo 
'Hello World!';
    }
}

class 
TheWorldIsNotEnough {
    use 
HelloWorld;
    public function 
sayHello() {
        echo 
'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

L'exemple ci-dessus va afficher :

Hello Universe!

Multiples Traits

Une classe peut utiliser de multiples Traits en les déclarant avec le mot-clé use, séparés par des virgules.

Exemple #4 Utilisation de plusieurs Traits

<?php
trait Hello {
    public function 
sayHello() {
        echo 
'Hello ';
    }
}

trait 
World {
    public function 
sayWorld() {
        echo 
'World';
    }
}

class 
MyHelloWorld {
    use 
HelloWorld;
    public function 
sayExclamationMark() {
        echo 
'!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

L'exemple ci-dessus va afficher :

Hello World!

Résolution des conflits

Si deux Traits insèrent une méthode avec le même nom, une erreur fatale est levée si le conflit n'est pas explicitement résolu.

Pour résoudre un conflit de nommage entre des Traits utilisés dans la même classe, il faut utiliser l'opérateur insteadof pour choisir une des méthodes en conflit.

Puisque ce principe ne permet que d'exclure des méthodes, l'opérateur as peut être utilisé pour permettre l'inclusion d'une des méthodes conflictuelles sous un autre nom.

Exemple #5 Résolution des conflits

Dans cet exemple, la classe Talker utilise les traits A et B. Comme A et B ont des méthodes conflictuelles, on indique que l'on souhaite utiliser la variante de smallTalk depuis le trait B, et la variante de bigTalk depuis le trait A.

La classe Aliased_Talker utilise l'opérateur as pour être capable d'utiliser l'implementation bigTalk de B sous un alias supplémentaire talk.

<?php
trait {
    public function 
smallTalk() {
        echo 
'a';
    }
    public function 
bigTalk() {
        echo 
'A';
    }
}

trait 
{
    public function 
smallTalk() {
        echo 
'b';
    }
    public function 
bigTalk() {
        echo 
'B';
    }
}

class 
Talker {
    use 
A{
        
B::smallTalk insteadof A;
        
A::bigTalk insteadof B;
    }
}

class 
Aliased_Talker {
    use 
A{
        
B::smallTalk insteadof A;
        
A::bigTalk insteadof B;
        
B::bigTalk as talk;
    }
}
?>

Changer la visibilité des méthodes

En utilisant la syntaxe as, vous pouvez aussi ajuster la visibilité de la méthode dans la classe qui l'utilise.

Exemple #6 Changer la visibilité des méthodes

<?php
trait HelloWorld {
    public function 
sayHello() {
        echo 
'Hello World!';
    }
}

// Modification de la visibilité de la méthode sayHello
class MyClass1 {
    use 
HelloWorld sayHello as protected; }
}

// Utilisation d'un alias lors de la modification de la visibilité
// La visibilité de la méthode sayHello n'est pas modifiée
class MyClass2 {
    use 
HelloWorld sayHello as private myPrivateHello; }
}
?>

Traits Composés depuis d'autres Traits

Tout comme les classes peuvent utiliser des traits, d'autres traits le peuvent aussi. Un trait peut donc utiliser d'autres traits et hériter de tout ou d'une partie de ceux-ci.

Exemple #7 Traits Composés depuis d'autres Traits

<?php
trait Hello {
    public function 
sayHello() {
        echo 
'Hello ';
    }
}

trait 
World {
    public function 
sayWorld() {
        echo 
'World!';
    }
}

trait 
HelloWorld {
    use 
HelloWorld;
}

class 
MyHelloWorld {
    use 
HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

L'exemple ci-dessus va afficher :

Hello World!

Méthodes abstraites dans les Traits

Les traits supportent l'utilisation de méthodes abstraites afin d'imposer des contraintes aux classes sous-jacentes.

Exemple #8 Obligations requises par les méthodes abstraites

<?php
trait Hello {
    public function 
sayHelloWorld() {
        echo 
'Hello'.$this->getWorld();
    }
    abstract public function 
getWorld();
}

class 
MyHelloWorld {
    private 
$world;
    use 
Hello;
    public function 
getWorld() {
        return 
$this->world;
    }
    public function 
setWorld($val) {
        
$this->world $val;
    }
}
?>

Attributs statiques dans les Traits

Traits peut définir à la fois des membres statiques, et des méthodes statiques.

Exemple #9 Variables statiques

<?php
trait Counter {
    public function 
inc() {
        static 
$c 0;
        
$c $c 1;
        echo 
"$c\n";
    }
}

class 
C1 {
    use 
Counter;
}

class 
C2 {
    use 
Counter;
}

$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

Exemple #10 Méthodes statiques

<?php
trait StaticExample {
    public static function 
doSomething() {
        return 
'Doing something';
    }
}

class 
Example {
    use 
StaticExample;
}

Example::doSomething();
?>

Propriétés

Les traits peuvent aussi définir des propriétés.

Exemple #11 Définir des propriétes

<?php
trait PropertiesTrait {
    public 
$x 1;
}

class 
PropertiesExample {
    use 
PropertiesTrait;
}

$example = new PropertiesExample;
$example->x;
?>

Si un trait définit une propriété, alors la classe ne peut pas définir une propriété de même nom ; sinon, une erreur sera levée. Il s'agira d'une erreur de type E_STRICT si la définition dans la classe est compatible (même visibilité et valeur initiale), et d'une erreur fatale dans les autres cas.

Exemple #12 Résolution des conflits

<?php
trait PropertiesTrait {
    public 
$same true;
    public 
$different false;
}

class 
PropertiesExample {
    use 
PropertiesTrait;
    public 
$same true// Strict Standards
    
public $different true// Fatal error
}
?>
add a note add a note

User Contributed Notes 28 notes

up
122
Safak Ozpinar / safakozpinar at gmail
2 years ago
Unlike inheritance; if a trait has static properties, each class using that trait has independent instances of those properties.

Example using parent class:
<?php
class TestClass {
    public static
$_bar;
}
class
Foo1 extends TestClass { }
class
Foo2 extends TestClass { }
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo
Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World
?>

Example using trait:
<?php
trait TestTrait {
    public static
$_bar;
}
class
Foo1 {
    use
TestTrait;
}
class
Foo2 {
    use
TestTrait;
}
Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo
Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: Hello World
?>
up
54
Stefan W
1 year ago
Note that the "use" operator for traits (inside a class) and the "use" operator for namespaces (outside the class) resolve names differently. "use" for namespaces always sees its arguments as absolute (starting at the global namespace):

<?php
namespace Foo\Bar;
use
Foo\Test// means \Foo\Test - the initial \ is optional
?>

On the other hand, "use" for traits respects the current namespace:

<?php
namespace Foo\Bar;
class
SomeClass {
    use
Foo\Test;   // means \Foo\Bar\Foo\Test
}
?>

Together with "use" for closures, there are now three different "use" operators. They all mean different things and behave differently.
up
47
chris dot rutledge at gmail dot com
2 years ago
It may be worth noting here that the magic constant __CLASS__ becomes even more magical - __CLASS__ will return the name of the class in which the trait is being used.

for example

<?php
trait sayWhere {
    public function
whereAmI() {
        echo
__CLASS__;
    }
}

class
Hello {
    use
sayWHere;
}

class
World {
    use
sayWHere;
}

$a = new Hello;
$a->whereAmI(); //Hello

$b = new World;
$b->whereAmI(); //World
?>

The magic constant __TRAIT__ will giev you the name of the trait
up
48
greywire at gmail dot com
2 years ago
The best way to understand what traits are and how to use them is to look at them for what they essentially are:  language assisted copy and paste.

If you can copy and paste the code from one class to another (and we've all done this, even though we try not to because its code duplication) then you have a candidate for a trait.
up
20
atorich at gmail dot com
1 year ago
add to "chris dot rutledge at gmail dot com":
__CLASS__ will return the name of the class in which the trait is being used (!) not the class in which trait method is being called:

<?php
trait TestTrait {
    public function
testMethod() {
        echo
"Class: " . __CLASS__ . PHP_EOL;
        echo
"Trait: " . __TRAIT__ . PHP_EOL;
    }
}

class
BaseClass {
    use
TestTrait;
}

class
TestClass extends BaseClass {

}

$t = new TestClass();
$t->testMethod();

//Class: BaseClass
//Trait: TestTrait
up
12
Edward
2 years ago
The difference between Traits and multiple inheritance is in the inheritance part.   A trait is not inherited from, but rather included or mixed-in, thus becoming part of "this class".   Traits also provide a more controlled means of resolving conflicts that inevitably arise when using multiple inheritance in the few languages that support them (C++).  Most modern languages are going the approach of a "traits" or "mixin" style system as opposed to multiple-inheritance, largely due to the ability to control ambiguities if a method is declared in multiple "mixed-in" classes.

Also, one can not "inherit" static member functions in multiple-inheritance.
up
22
t8 at AT pobox dot com
2 years ago
Another difference with traits vs inheritance is that methods defined in traits can access methods and properties of the class they're used in, including private ones.

For example:
<?php
trait MyTrait
{
  protected function
accessVar()
  {
    return
$this->var;
  }

}

class
TraitUser
{
  use
MyTrait;

  private
$var = 'var';

  public function
getVar()
  {
    return
$this->accessVar();
  }
}

$t = new TraitUser();
echo
$t->getVar(); // -> 'var'                                                                                                                                                                                                                         

?>
up
34
ryan at derokorian dot com
2 years ago
Simple singleton trait.

<?php

trait singleton {   
   
/**
     * private construct, generally defined by using class
     */
    //private function __construct() {}
   
   
public static function getInstance() {
        static
$_instance = NULL;
       
$class = __CLASS__;
        return
$_instance ?: $_instance = new $class;
    }
   
    public function
__clone() {
       
trigger_error('Cloning '.__CLASS__.' is not allowed.',E_USER_ERROR);
    }
   
    public function
__wakeup() {
       
trigger_error('Unserializing '.__CLASS__.' is not allowed.',E_USER_ERROR);
    }
}

/**
* Example Usage
*/

class foo {
    use
singleton;
   
    private function
__construct() {
       
$this->name = 'foo';
    }
}

class
bar {
    use
singleton;
   
    private function
__construct() {
       
$this->name = 'bar';
    }
}

$foo = foo::getInstance();
echo
$foo->name;

$bar = bar::getInstance();
echo
$bar->name;
up
5
Kristof
6 months ago
don't forget you can create complex (embedded) traits as well

<?php
trait Name {
 
// ...
}
trait
Address {
 
// ...
}
trait
Telephone {
 
// ...
}
trait
Contact {
  use
Name, Address, Telephone;
}
class
Customer {
  use
Contact;
}
class
Invoce {
  use
Contact;
}
?>
up
13
karolis at iwsolutions dot ie
2 years ago
Not very obvious but trait methods can be called as if they were defined as static methods in a regular class

<?php
trait Foo {
    function
bar() {
        return
'baz';
    }
}

echo
Foo::bar(),"\\n";
?>
up
16
Anonymous
2 years ago
Traits can not implement interfaces.
(should be obvious, but tested is tested)
up
12
Jason dot Hofer dot deletify dot this dot part at gmail dot com
2 years ago
A (somewhat) practical example of trait usage.

Without traits:

<?php

class Controller {
 
/* Controller-specific methods defined here. */
}

class
AdminController extends Controller {
 
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods defined here. */
}

class
CrudController extends Controller {
 
/* Controller-specific methods inherited from Controller. */
  /* CRUD-specific methods defined here. */
}

class
AdminCrudController extends CrudController {
 
/* Controller-specific methods inherited from Controller. */
  /* CRUD-specific methods inherited from CrudController. */
  /* (!!!) Admin-specific methods copied and pasted from AdminController. */
}

?>

With traits:

<?php

class Controller {
 
/* Controller-specific methods defined here. */
}

class
AdminController extends Controller {
 
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods defined here. */
}

trait
CrudControllerTrait {
 
/* CRUD-specific methods defined here. */
}

class
AdminCrudController extends AdminController {
  use
CrudControllerTrait;
 
/* Controller-specific methods inherited from Controller. */
  /* Admin-specific methods inherited from AdminController. */
  /* CRUD-specific methods defined by CrudControllerTrait. */
}

?>
up
8
anthony bishopric
2 years ago
The magic method __call works as expected using traits.

<?php
trait Call_Helper{
   
    public function
__call($name, $args){
        return
count($args);
    }
}

class
Foo{
    use
Call_Helper;
}

$foo = new Foo();
echo
$foo->go(1,2,3,4); // echoes 4
up
8
D. Marti
2 years ago
Traits are useful for strategies, when you want the same data to be handled (filtered, sorted, etc) differently.

For example, you have a list of products that you want to filter out based on some criteria (brands, specs, whatever), or sorted by different means (price, label, whatever). You can create a sorting trait that contains different functions for different sorting types (numeric, string, date, etc). You can then use this trait not only in your product class (as given in the example), but also in other classes that need similar strategies (to apply a numeric sort to some data, etc).

<?php
trait SortStrategy {
    private
$sort_field = null;
    private function
string_asc($item1, $item2) {
        return
strnatcmp($item1[$this->sort_field], $item2[$this->sort_field]);
    }
    private function
string_desc($item1, $item2) {
        return
strnatcmp($item2[$this->sort_field], $item1[$this->sort_field]);
    }
    private function
num_asc($item1, $item2) {
        if (
$item1[$this->sort_field] == $item2[$this->sort_field]) return 0;
        return (
$item1[$this->sort_field] < $item2[$this->sort_field] ? -1 : 1 );
    }
    private function
num_desc($item1, $item2) {
        if (
$item1[$this->sort_field] == $item2[$this->sort_field]) return 0;
        return (
$item1[$this->sort_field] > $item2[$this->sort_field] ? -1 : 1 );
    }
    private function
date_asc($item1, $item2) {
       
$date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
       
$date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if (
$date1 == $date2) return 0;
        return (
$date1 < $date2 ? -1 : 1 );
    }
    private function
date_desc($item1, $item2) {
       
$date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
       
$date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if (
$date1 == $date2) return 0;
        return (
$date1 > $date2 ? -1 : 1 );
    }
}

class
Product {
    public
$data = array();
   
    use
SortStrategy;
   
    public function
get() {
       
// do something to get the data, for this ex. I just included an array
       
$this->data = array(
           
101222 => array('label' => 'Awesome product', 'price' => 10.50, 'date_added' => '2012-02-01'),
           
101232 => array('label' => 'Not so awesome product', 'price' => 5.20, 'date_added' => '2012-03-20'),
           
101241 => array('label' => 'Pretty neat product', 'price' => 9.65, 'date_added' => '2012-04-15'),
           
101256 => array('label' => 'Freakishly cool product', 'price' => 12.55, 'date_added' => '2012-01-11'),
           
101219 => array('label' => 'Meh product', 'price' => 3.69, 'date_added' => '2012-06-11'),
        );
    }
   
    public function
sort_by($by = 'price', $type = 'asc') {
        if (!
preg_match('/^(asc|desc)$/', $type)) $type = 'asc';
        switch (
$by) {
            case
'name':
               
$this->sort_field = 'label';
               
uasort($this->data, array('Product', 'string_'.$type));
            break;
            case
'date':
               
$this->sort_field = 'date_added';
               
uasort($this->data, array('Product', 'date_'.$type));
            break;
            default:
               
$this->sort_field = 'price';
               
uasort($this->data, array('Product', 'num_'.$type));
        }
    }
}

$product = new Product();
$product->get();
$product->sort_by('name');
echo
'<pre>'.print_r($product->data, true).'</pre>';
?>
up
3
ryanhanekamp at yahoo dot com
2 years ago
Using AS on a __construct method (and maybe other magic methods) is really, really bad. The problem is that is doesn't throw any errors, at least in 5.4.0. It just sporadically resets the connection. And when I say "sporadically," I mean that arbitrary changes in the preceding code can cause the browser connection to reset or not reset *consistently*, so that subsequent page refreshes will continue to hang, crash, or display perfectly in the same fashion as the first load of the page after a change in the preceding code, but the slightest change in the code can change this state. (I believe it is related to precise memory usage.)

I've spent a good part of the day chasing down this one, and weeping every time commenting or even moving a completely arbitrary section of code would cause the connection to reset. It was just by luck that I decided to comment the

"__construct as primitiveObjectConstruct"

line and then the crashes went away entirely.

My parent trait constructor was very simple, so my fix this time was to copy the functionality into the child __construct. I'm not sure how I'll approach a more complicated parent trait constructor.
up
1
ryan dot yoosefi at gmail dot com
2 months ago
Visibility in traits is not shared between trait users.

<?php

trait T {
    protected
$secret = 1;
}

class
X {
    use
T;
    public function
peek ( Y $y ) {
        echo
$y->secret;
    }
}

class
Y {
    use
T;
}

(new
X)->peek(new Y); // Fatal:  Cannot access protected property Y::$secret
?>

This is as expected when thinking of traits as language assisted copy-paste.
up
1
contato at williamsantana dot com dot br
1 year ago
Please note that a trait cannot extend a class. Traits can only contain another traits by using 'use' keyword. Things like

<?php
   
trait DetailedException extends Exception {}
?>

will not work. Be careful.

Cheers.
up
0
angel dot ayora at gmail dot com
2 months ago
The traits can be used if are inherited from a parent class, but the trait still belong to parent class:

<?php

trait Singleton
{
    private static
$instance = null;

    public static function
singleton()
    {
        if(
self::$instance == null )
        {
           
self::$instance = new self();
        }
        return
self::$instance;
    }
}

class
A
{
    use
Singleton;
    private function
__construct(){}
}

class
B extends A
{
    private function
__construct(){}
}

$b = B::singleton();
echo
get_class($b); //Output: A

?>
up
0
qschuler at neosyne dot com
10 months ago
Note that you can omit a method's inclusion by excluding it from one trait in favor of the other and doing the exact same thing in the reverse way.

<?php

trait A {
    public function
sayHello()
    {
        echo
'Hello from A';
    }

    public function
sayWorld()
    {
        echo
'World from A';
    }
}

trait
B {
    public function
sayHello()
    {
        echo
'Hello from B';
    }

    public function
sayWorld()
    {
        echo
'World from B';
    }
}

class
Talker {
    use
A, B {
       
A::sayHello insteadof B;
       
A::sayWorld insteadof B;
       
B::sayWorld insteadof A;
    }
}

$talker = new Talker();
$talker->sayHello();
$talker->sayWorld();

?>

The method sayHello is imported, but the method sayWorld is simply excluded.
up
0
tomasz at marcinkowski dot pl
10 months ago
Unlike the __CLASS__ constant, which returns name of a class implementing a trait, the __METHOD__ constant returns the trait method name. You might find it useful.

Example:

<?php

namespace XXX;

trait
Ta {
  public function
test1() {
    return
sprintf('class: %s, method: %s, trait: %s', __CLASS__, __METHOD__, __TRAIT__);
  }
}

class
A {
  use
Ta;
}

$a = new A();
var_dump($a->test1()); // class: XXX\A, method: XXX\Ta::test1, trait: XXX\Ta

?>
up
0
Oddant
1 year ago
I think it's obvious to notice that using 'use' followed by the traits name must be seen as just copying/pasting lines of code into the place where they are used.
up
-2
majoro chitetskoy at gmail dot com
1 year ago
Some extreme Trait testing, which anyone can find useful. This involves what can be called as "Trait Inheritance" though I doubt if that is a proper word. This shows how to have some sort of inheritance in Traits.

Snippet from one complex Tristan Engine code.

<?php
/**
* Trait and Helper Backbone class
*/
trait Foo_HlpBbT {
      function 
mnInfo_gst($x=null, $c=false){
        echo
"Foo_HlpBbT has been called\n";
      }
}

/**
* Base Archvie
*/
class Foo_BaseArchive {
    use
Foo_HlpBbT;
   
   
// accessor properties
   
public    $_mnInfo;
}

/**
* Testing Archive
*/
class Foo_ItemArchvie extends
   
Foo_BaseArchive
{
}

/**
* Testing Archive 2
*/
/**
* The base handler for sub base handler
*/
trait Foo_Item_HlpBbT {
    use
Foo_HlpBbT;

    function
mnInfo_gst($x=null, $c=false){
       
parent::mnInfo_gst($x,$c);
        echo
"Foo_Item_HlpBbT is called.\n";
    }
}

/**
* The base handler for sub base handler
*/
trait Foo_Item_HlpBbT2 {
    use
Foo_Item_HlpBbT {
       
Foo_Item_HlpBbT::mnInfo_gst as _e1_mnInfo_gst;
    }

   
// We need that the Foo_HlpBbT::mnInfo_gst, Foo_Item_HlpBbT::mnInfo_gst and this mnInfo_gst is called.
    // Troubles here, only the Foo_HlpBbT and this is called, the Foo_Item_HlpBbT is skipped.
    // So it's important that if necessary, the function that is intended to be "overriden" from
    // the trait inheritances be aliased like what we did to mnInfo_gst.
   
function mnInfo_gst($x=null, $c=false){
       
$this->_e1_mnInfo_gst($x,$c);
        echo
"Foo_Item_HlpBbT2 is called.\n";
    }
}

/**
* The base handler for sub base handler
*/
trait Foo_Item_HlpBbT3 {
    use
Foo_Item_HlpBbT2 {
       
Foo_Item_HlpBbT2::mnInfo_gst as _e2_mnInfo_gst;
    }

   
// Another deeper Trait declaration
   
function mnInfo_gst($x=null, $c=false){
       
$this->_e2_mnInfo_gst($x,$c);
        echo
"Foo_Item_HlpBbT3 is called.\n";
    }
}

/**
* Item Archive
*/
class Foo_Item_ItemArchive extends
   
Foo_BaseArchive
{
    use
Foo_Item_HlpBbT3;
}

// Testing na
$tang = new Foo_Item_ItemArchive();
$tang->mnInfo_gst();
?>
outputs:

Foo_HlpBbT has been called
Foo_Item_HlpBbT is called.
Foo_Item_HlpBbT2 is called.
Foo_Item_HlpBbT3 is called.
up
0
Serafim
1 year ago
Another useful property of traits:
<?php
namespace Traits;
trait
Properties{
    public function
__get($var){
       
$var = '_' . $var;
       
$getter = '_get' . $var;
       
        if(
method_exists($this, $getter)){
            try{
               
$val = $this->$getter();
            }catch(\
Exception $e){
                throw new \
Exception($e);
            }
            return
$val;
        }
        throw new \
Exception('Can not get property: ' . $var . ', method ' . $getter . ' not exists');
    }
   
    public function
__set($var, $val){
       
$var = '_' . $var;
       
$setter = '_set' . $var;
       
        if(
method_exists($this->$setter) && isset($this->$var)){
            try{
               
$setval = $this->$setter($val);
            }catch(\
Exception $e){
                throw new \
Exception($e);
            }
           
$this->$var = ($setval === NULL) ? $this->$var : $setval;
        }else{
            throw new \
Exception('Can not set property: ' . $var . ', method ' . $setter . ' not exists');
        }
    }
}

class
Some{
  use \
Chidori\Traits\Properties;
 
 
// Magic begin
 
protected $_var = 42;
  protected function
_get_var(){ return $this->_var; }
  protected function
_set_var($val){ return NULL; }
}

$s = new Some();
$s->var = 23; \\ set value
echo $s->var; \\ return 42? where is my 23? =)
?>
up
0
artur at webprojektant dot pl
2 years ago
Trait can not have the same name as class because it will  show: Fatal error: Cannot redeclare class
up
-3
dario dot masamune at gmail dot com
2 years ago
Just in case someone was wondering, traits can be inside namespaces too! Cool!!
up
-1
atorich at gmail dot com
1 year ago
add to "chris dot rutledge at gmail dot com":
__CLASS__ will return the name of the class in which the trait is being used (!) not the class in which trait method is being called:

<?php
trait TestTrait {
    public function
testMethod() {
        echo
"Class: " . __CLASS__ . PHP_EOL;
        echo
"Trait: " . __TRAIT__ . PHP_EOL;
    }
}

class
BaseClass {
    use
TestTrait;
}

class
TestClass extends BaseClass {

}

$t = new TestClass();
$t->testMethod();

//Class: BaseClass
//Trait: TestTrait
up
-3
peter at icb dot at
1 year ago
You cannot use a trait whos name is in a variable like:
<?php
trait mytrait { public $x; }

$tr = 'mytrait';
class
myclass
{
  use
$tr;
  ...
}
?>

If you really need that, you have to use eval:
<?php
eval("
class my_tmp_class { use
$tr; }
"
);

class
myclass extends my_tmp_class { ... }
?>
up
-6
syzer3 at gmail dot com
1 year ago
Traits can be useful to create Fluent API
ex:
trait StaticMake
{
    public static function make()
    {
        return new static();
    }
}
class HelloWorld
{
use StaticMake;

   public function getHello()
   {
      return "Hello World";
   }
}
//now instead:
$theHello = new HelloWorld;
echo $theHello -> getHello();

//one may just use
echo HelloWorld:make() -> getHello();
To Top