Use trait in trait php

PHP implements a way to reuse code called Traits.

Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way which reduces complexity, and avoids the typical problems associated with multiple inheritance and Mixins.

A Trait is similar to a class, but only intended to group functionality in a fine-grained and consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional inheritance and enables horizontal composition of behavior; that is, the application of class members without requiring inheritance.

Example #1 Trait example

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

class

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

class

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

Precedence

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.

Example #2 Precedence Order Example

An inherited method from a base class is overridden by the method inserted into MyHelloWorld from the SayWorld Trait. The behavior is the same for methods defined in the MyHelloWorld class. The precedence order is that methods from the current class override Trait methods, which in turn override methods from the base class.

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();
?>

The above example will output:

Example #3 Alternate Precedence Order Example

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

class

TheWorldIsNotEnough {
    use 
HelloWorld;
    public function 
sayHello() {
        echo 
'Hello Universe!';
    }
}
$o = new TheWorldIsNotEnough();
$o->sayHello();
?>

The above example will output:

Multiple Traits

Multiple Traits can be inserted into a class by listing them in the use statement, separated by commas.

Example #4 Multiple Traits Usage

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();
?>

The above example will output:

Conflict Resolution

If two Traits insert a method with the same name, a fatal error is produced, if the conflict is not explicitly resolved.

To resolve naming conflicts between Traits used in the same class, the insteadof operator needs to be used to choose exactly one of the conflicting methods.

Since this only allows one to exclude methods, the as operator can be used to add an alias to one of the methods. Note the as operator does not rename the method and it does not affect any other method either.

Example #5 Conflict Resolution

In this example, Talker uses the traits A and B. Since A and B have conflicting methods, it defines to use the variant of smallTalk from trait B, and the variant of bigTalk from trait A.

The Aliased_Talker makes use of the as operator to be able to use B's bigTalk implementation under an additional alias talk.

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;
    }
}
?>

Changing Method Visibility

Using the as syntax, one can also adjust the visibility of the method in the exhibiting class.

Example #6 Changing Method Visibility

trait HelloWorld {
    public function 
sayHello() {
        echo 
'Hello World!';
    }
}
// Change visibility of sayHello
class MyClass1 {
    use 
HelloWorld sayHello as protected; }
}
// Alias method with changed visibility
// sayHello visibility not changed
class MyClass2 {
    use 
HelloWorld sayHello as private myPrivateHello; }
}
?>

Traits Composed from Traits

Just as classes can make use of traits, so can other traits. By using one or more traits in a trait definition, it can be composed partially or entirely of the members defined in those other traits.

Example #7 Traits Composed from Traits

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();
?>

The above example will output:

Abstract Trait Members

Traits support the use of abstract methods in order to impose requirements upon the exhibiting class. Public, protected, and private methods are supported. Prior to PHP 8.0.0, only public and protected abstract methods were supported.

Caution

A concrete class fulfills this requirement by defining a concrete method with the same name; its signature may be different.

Example #8 Express Requirements by Abstract Methods

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;
    }
}
?>

Static Trait Members

Traits can define static variables, static methods and static properties.

Note:

As of PHP 8.1.0, calling a static method, or accessing a static property directly on a trait is deprecated. Static methods and properties should only be accessed on a class using the trait.

Example #9 Static Variables

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
?>

Example #10 Static Methods

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

class

Example {
    use 
StaticExample;
}
Example::doSomething();
?>

Example #11 Static Properties

trait StaticExample {
    public static 
$static 'foo';
}

class

Example {
    use 
StaticExample;
}

echo

Example::$static;
?>

Properties

Traits can also define properties.

Example #12 Defining Properties

trait PropertiesTrait {
    public 
$x 1;
}

class

PropertiesExample {
    use 
PropertiesTrait;
}
$example = new PropertiesExample;
$example->x;
?>

If a trait defines a property then a class can not define a property with the same name unless it is compatible (same visibility and initial value), otherwise a fatal error is issued.

Example #13 Conflict Resolution

trait PropertiesTrait {
    public 
$same true;
    public 
$different false;
}

class

PropertiesExample {
    use 
PropertiesTrait;
    public 
$same true;
    public 
$different true// Fatal error
}
?>

Safak Ozpinar / safakozpinar at gmail

10 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:
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:
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
?>

greywire at gmail dot com

10 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.

Stefan W

9 years 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):

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

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

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.

chris dot rutledge at gmail dot com

10 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

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

qeremy (!) gmail

7 years ago

Keep in mind; "final" keyword is useless in traits when directly using them, unlike extending classes / abstract classes.

trait Foo {
    final public function
hello($s) { print "$s, hello!"; }
}
class
Bar {
    use
Foo;
   
// Overwrite, no error
   
final public function hello($s) { print "hello, $s!"; }
}

abstract class

Foo {
    final public function
hello($s) { print "$s, hello!"; }
}
class
Bar extends Foo {
   
// Fatal error: Cannot override final method Foo::hello() in ..
   
final public function hello($s) { print "hello, $s!"; }
}
?>

But this way will finalize trait methods as expected;

trait FooTrait {
    final public function
hello($s) { print "$s, hello!"; }
}
abstract class
Foo {
    use
FooTrait;
}
class
Bar extends Foo {
   
// Fatal error: Cannot override final method Foo::hello() in ..
   
final public function hello($s) { print "hello, $s!"; }
}
?>

t8 at AT pobox dot com

10 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:
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'                                                                                                                                                                                                                          ?>

rawsrc

4 years ago

About the (Safak Ozpinar / safakozpinar at gmail)'s great note, you can still have the same behavior than inheritance using trait with this approach :
trait TestTrait {
    public static
$_bar;
}

class

FooBar {
    use
TestTrait;
}

class

Foo1 extends FooBar {

}
class

Foo2 extends FooBar {

}

Foo1::$_bar = 'Hello';
Foo2::$_bar = 'World';
echo
Foo1::$_bar . ' ' . Foo2::$_bar; // Prints: World World

canufrank

6 years ago

A number of the notes make incorrect assertions about trait behaviour because they do not extend the class.

So, while "Unlike inheritance; if a trait has static properties, each class using that trait has independent instances of those properties.

Example using parent class:
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:
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
?>"

shows a correct example, simply adding
require_once('above');
class
Foo3 extends Foo2 {
}
Foo3::$_bar = 'news';
echo
Foo1::$_bar . ' ' . Foo2::$_bar . ' ' . Foo3::$_bar; // Prints: Hello news newsI think the best conceptual model of an incorporated trait is an advanced insertion of text, or as someone put it "language assisted copy and paste." If Foo1 and Foo2 were defined with $_bar, you would not expect them to share the instance. Similarly, you would expect Foo3 to share with Foo2, and it does.Viewing this way explains away a lot of  the 'quirks' that are observed above with final, or subsequently declared private vars,

balbuf

6 years ago

(It's already been said, but for the sake of searching on the word "relative"...)

The "use" keyword to import a trait into a class will resolve relative to the current namespace and therefore should include a leading slash to represent a full path, whereas "use" at the namespace level is always absolute.

marko at newvibrations dot net

5 years ago

As already noted, static properties and methods in trait could be accessed directly using trait. Since trait is language assisted c/p, you should be aware that static property from trait will be initialized to the value trait property had in the time of class declaration.

Example:

trait Beer {
    protected static
$type = 'Light';
    public static function
printed(){
        echo static::
$type.PHP_EOL;
    }
    public static function
setType($type){
        static::
$type = $type;
    }
}

class

Ale {
    use
Beer;
}
Beer::setType("Dark");

class

Lager {
    use
Beer;
}
Beer::setType("Amber");header("Content-type: text/plain");Beer::printed();  // Prints: Amber
Ale::printed();   // Prints: Light
Lager::printed(); // Prints: Dark?>

qschuler at neosyne dot com

8 years 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.

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.

Edward

10 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.

ryan at derokorian dot com

10 years ago

Simple singleton trait.

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;

cody at codysnider dot com

5 years ago

/*
DocBlocks pertaining to the class or trait will NOT be carried over when applying the trait.

Results trying a couple variations on classes with and without DocBlocks that use a trait with a DocBlock
*/

/**
* @Entity
*/
trait Foo
{
    protected
$foo;
}
/**
* @HasLifecycleCallbacks
*/
class Bar
{
    use \
Foo;

        protected

$bar;
}

class

MoreBar
{
    use \
Foo;

        protected

$moreBar;
}
$w = new \ReflectionClass('\Bar');
echo
$w->getName() . ":\r\n";
echo
$w->getDocComment() . "\r\n\r\n";$x = new \ReflectionClass('\MoreBar');
echo
$x->getName() . ":\r\n";
echo
$x->getDocComment() . "\r\n\r\n";$barObj = new \Bar();
$y = new \ReflectionClass($barObj);
echo
$y->getName() . ":\r\n";
echo
$y->getDocComment() . "\r\n\r\n";

foreach(

$y->getTraits() as $traitObj) {
    echo
$y->getName() . " ";
    echo
$traitObj->getName() . ":\r\n";
    echo
$traitObj->getDocComment() . "\r\n";
}
$moreBarObj = new \MoreBar();
$z = new \ReflectionClass($moreBarObj);
echo
$z->getName() . " ";
echo
$z->getDocComment() . "\r\n\r\n";

foreach(

$z->getTraits() as $traitObj) {
    echo
$z->getName() . " ";
    echo
$traitObj->getName() . ":\r\n";
    echo
$traitObj->getDocComment() . "\r\n";
}

Kristof

8 years ago

don't forget you can create complex (embedded) traits as well

trait Name {
 
// ...
}
trait
Address {
 
// ...
}
trait
Telephone {
 
// ...
}
trait
Contact {
  use
Name, Address, Telephone;
}
class
Customer {
  use
Contact;
}
class
Invoce {
  use
Contact;
}
?>

guidobelluomo at gmail dot com

2 years ago

If you override a method which was defined by a trait, calling the parent method will also call the trait's override. Therefore if you need to derive from a class which has a trait, you can extend the class without losing the trait's functionality:

trait ExampleTrait
{
    public function
output()
    {
       
parent::output();
        echo
"bar
"
;
    }
}

class

Foo
{
    public function
output()
    {
        echo
"foo
"
;
    }
}

class

FooBar extends Foo
{
    use
ExampleTrait;
}

class

FooBarBaz extends FooBar
{
    use
ExampleTrait;
    public function
output()
    {
       
parent::output();
        echo
"baz";
    }
}

(new

FooBarBaz())->output();
?>

Output:
foo
bar
baz

katrinaelaine6 at gmail dot com

4 years ago

Adding to "atorich at gmail dot com":

The behavior of the magic constant __CLASS__ when used in traits is as expected if you understand traits and late static binding (http://php.net/manual/en/language.oop5.late-static-bindings.php).

$format

= 'Class: %-13s | get_class(): %-13s | get_called_class(): %-13s%s';

trait

TestTrait {
    public function
testMethod() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }

        public static function

testStatic() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

trait

DuplicateTrait {
    public function
duplMethod() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }

        public static function

duplStatic() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

abstract class

AbstractClass {

        use

DuplicateTrait;

        public function

absMethod() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }

        public static function

absStatic() {
        global
$format;
       
printf($format, __CLASS__, get_class(), get_called_class(), PHP_EOL);
    }
}

class

BaseClass extends AbstractClass {
    use
TestTrait;
}

class

TestClass extends BaseClass { }$t = new TestClass();$t->testMethod();
TestClass::testStatic();$t->absMethod();
TestClass::absStatic();$t->duplMethod();
TestClass::duplStatic();?>

Will output:

Class: BaseClass     | get_class(): BaseClass     | get_called_class(): TestClass   
Class: BaseClass     | get_class(): BaseClass     | get_called_class(): TestClass   
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass   
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass   
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass   
Class: AbstractClass | get_class(): AbstractClass | get_called_class(): TestClass

Since Traits are considered literal "copying/pasting" of code, it's clear how the methods defined in DuplicateTrait give the same results as the methods defined in AbstractClass.

D. Marti

9 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).

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
'
'.print_r($product->data, true).'
'
;
?>

yeu_ym at yahoo dot com

3 years ago

Here is an example how to work with visiblity and conflicts.

trait A
{
    private function
smallTalk()
    {
        echo
'a';
    }

    private function

bigTalk()
    {
        echo
'A';
    }
}

trait

B
{
    private function
smallTalk()
    {
        echo
'b';
    }

    private function

bigTalk()
    {
        echo
'B';
    }
}

trait

C
{
    public function
smallTalk()
    {
        echo
'c';
    }

    public function

bigTalk()
    {
        echo
'C';
    }
}

class

Talker
{
    use
A, B, C {
       
//visibility for methods that will be involved in conflict resolution
       
B::smallTalk as public;
       
A::bigTalk as public;//conflict resolution
       
B::smallTalk insteadof A, C;
       
A::bigTalk insteadof B, C;//aliases with visibility change
       
B::bigTalk as public Btalk;
       
A::smallTalk as public asmalltalk;//aliases only, methods already defined as public
       
C::bigTalk as Ctalk;
       
C::smallTalk as cmallstalk;
    }

}

(new

Talker)->bigTalk();//A
(new Talker)->Btalk();//B
(new Talker)->Ctalk();//C(new Talker)->asmalltalk();//a
(new Talker)->smallTalk();//b
(new Talker)->cmallstalk();//c

Carlos Alberto Bertholdo Carucce

6 years ago

If you want to resolve name conflicts and also change the visibility of a trait method, you'll need to declare both in the same line:

trait testTrait{

        public function test(){
        echo 'trait test';
    }

    }

class myClass{

        use testTrait {
        testTrait::test as private testTraitF;
    }

        public function test(){
        echo 'class test';
        echo '
';
        $this->testTraitF();
    }

    }

$obj = new myClass();
$obj->test(); //prints both 'trait test' and 'class test'
$obj->testTraitF(); //The method is not accessible (Fatal error: Call to private method myClass::testTraitF() )

Oddant

9 years 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.

bscheshirwork at gmail dot com

4 years ago

https://3v4l.org/mFuQE

1. no deprecate if same-class-named method get from trait
2. replace same-named method ba to aa in C

trait ATrait {
    public function a(){
        return 'Aa';
    }
}

trait BTrait {
    public function a(){
        return 'Ba';
    }
}

class C {
    use ATrait{
        a as aa;
    }
    use BTrait{
        a as ba;
    }

        public function a() {
        return static::aa() . static::ba();
    }
}

$o = new C;
echo $o->a(), "\n";

class D {
    use ATrait{
        ATrait::a as aa;
    }
    use BTrait{
        BTrait::a as ba;
    }

        public function a() {
        return static::aa() . static::ba();
    }
}

$o = new D;
echo $o->a(), "\n";

class E {
    use ATrait{
        ATrait::a as aa;
        ATrait::a insteadof BTrait;
    }
    use BTrait{
        BTrait::a as ba;
    }

        public function e() {
        return static::aa() . static::ba();
    }
}

$o = new E;
echo $o->e(), "\n";

class F {
    use ATrait{
        a as aa;
    }
    use BTrait{
        a as ba;
    }

        public function f() {
        return static::aa() . static::ba();
    }
}

$o = new F;
echo $o->f(), "\n";

AaAa
AaBa

Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; E has a deprecated constructor in /in/mFuQE on line 48
AaBa

Fatal error: Trait method a has not been applied, because there are collisions with other trait methods on F in /in/mFuQE on line 65

84td84 at gmail dot com

7 years ago

A note to 'Beispiel #9 Statische Variablen'. A trait can also have a static property:

trait Counter {
    static $trvar=1;

    public static function stfunc() {
        echo "Hello world!"
    }
}

class C1 {
    use Counter;
}

print "\nTRVAR: " . C1::$trvar . "\n";   //prints 1

$obj = new C1();
C1::stfunc();   //prints  Hello world!
$obj->stfunc();   //prints Hello world!

A static property (trvar) can only be accessed using the classname (C1).
But a static function (stfunc) can be accessed using the classname or the instance ($obj).

Can a trait use another trait PHP?

It is not allowed to instantiate a trait on its own. So a trait is just a container for a group of methods that you can reuse in another classes.

What is the use of trait in PHP?

In PHP, a trait is a way to enable developers to reuse methods of independent classes that exist in different inheritance hierarchies. Simply put, traits allow you to create desirable methods in a class setting, using the trait keyword. You can then inherit this class through the use keyword.

Can I create object of trait in PHP?

A trait is similar to a class, but it is only for grouping methods in a fine-grained and consistent way. PHP does not allow you to create an instance of a Trait like an instance of a class. And there is no such concept of an instance of a trait.

Can a trait have a constructor PHP?

Unlike traits in Scala, traits in PHP can have a constructor but it must be declared public (an error will be thrown if is private or protected). Anyway, be cautious when using constructors in traits, though, because it may lead to unintended collisions in the composing classes.