Home  >  Article  >  Backend Development  >  PHP classes and objects - Traits

PHP classes and objects - Traits

伊谢尔伦
伊谢尔伦Original
2016-11-23 14:06:57956browse

Since PHP 5.4.0, PHP has implemented a method of code reuse called traits.

Traits is a code reuse mechanism prepared for single inheritance languages ​​like PHP. Traits are designed to reduce the constraints of single-inheritance languages ​​and allow developers to freely reuse method sets in independent classes within different hierarchies. The semantics of traits and class composition define a way to reduce complexity and avoid the typical problems associated with traditional multiple inheritance and mixins.

Traits are similar to a class, but are simply designed to combine functionality in a fine-grained and consistent way. Trait cannot be instantiated by itself. It adds a combination of horizontal features to traditional inheritance; that is, members of application classes do not need to be inherited.

Example #1 Trait example

trait ezcReflectionReturnInfo{
    function getReturnType(){}
    function getReturnDescription(){}
}
class ezcReflectionMethod extends ReflectionMethod{
    use ezcReflectionReturnInfo;
}
class ezcReflectionFunction extends ReflectionFunction{
    use ezcReflectionReturnInfo;
}

Priority

Members inherited from the base class are overridden by members inserted by the trait. The order of precedence is that members from the current class override the trait's methods, and the trait overrides the inherited methods.

Example #2 Priority example

Members inherited from the base class are overridden by the MyHelloWorld method in the inserted SayWorld Trait. Its behavior is consistent with the methods defined in the MyHelloWorld class. The priority order is that the methods in the current class will override the trait method, and the trait method will override the method in 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();

Output result:

Hello World!

Example #3 Another example of priority order

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

Output result:

Hello Universe!

Multiple traits

Separated by commas, multiple traits are listed in the use statement, and they can all be inserted into a class.

Example #4 Usage of multiple traits

trait Hello{
    public function sayHello(){
        echo 'Hello ';
    }
}
trait World{
    public function sayWorld(){
        echo 'World';
    }
}
class MyHelloWorld{
    use Hello,World;
    public function sayExclamationMark(){
        echo '!';
    }
}
$o = new MyHelloWorld();
$o -> sayHello();
$o -> sayWorld();
$o -> sayExclamationMark();

Output result:

Hello World!

Conflict resolution

If two traits insert a method with the same name, a fatal error will occur if the conflict is not resolved explicitly mistake.

In order to resolve the naming conflict of multiple traits in the same class, you need to use the insteadof operator to explicitly specify which of the conflicting methods to use.

The above method only allows to exclude other methods. The as operator can introduce one of the conflicting methods under another name.

Example #5 Conflict resolution

In this example, Talker uses traits A and B. Since A and B have conflicting methods, they define using smallTalk from trait B and bigTalk from trait A.

Aliased_Talker uses the as operator to define talk as an alias of B's ​​bigTalk.

trait A{
    public function smallTalk(){
        echo 'a';
    }
    public function bigTalk(){
        echo 'A';
    }
}
trait B{
    public function smallTalk(){
        echo 'b';
    }
    public function bigTalk(){
        echo 'B';
    }
}
class Talker{
    use A,B{
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}
class Aliased_Talker{
    use A,B{
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
$t = new Talker;
$t->smallTalk(); //b
$t->bigTalk(); //A
$at = new Aliased_Talker;
$at->smallTalk(); //b
$at->bigTalk(); //A
$at->talk(); //B

Modify the access control of the method

Using the as syntax can also be used to adjust the access control of the method.

Example #6 Modify method access control

trait HelloWorld{
    public function sayHello(){
        echo 'Hello World!';
    }
}
//修改sayHello的访问控制
class MyClass1{
    use HelloWorld{
        sayHello as protected;
    }
}
//给方法一个改变了访问控制的别名
//原版sayHello的访问控制则没有发生变化
class MyClass2{
    use HelloWorld{sayHello as private myPrivateHello;}
}

Compose traits from traits

Just as classes can use traits, other traits can also use traits. By using one or more traits when a trait is defined, it can combine some or all members of other traits.

Example #7 Compose trait from trait

trait Hello{
    public function sayHello(){
        echo 'Hello ';
    }
}
trait World{
    public function sayWorld(){
        echo 'World!';
    }
}
trait HelloWorld{
    use Hello,World;
}
class MyHelloWorld{
    use HelloWorld;
}
$o = new MyHelloWorld;
$o -> sayHello();
$o -> sayWorld();

Output result:

Hello World!

Abstract members of Trait

In order to impose mandatory requirements on the classes used, traits support the use of abstract methods.

Example #8 represents enforcement through 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 members of Trait

Static variables can be referenced by trait methods, but cannot be defined by trait. But traits can define static methods for the classes they are used in.

Example #9 Static variable

trait Counter{
    public function inc(){
        static $c = 0;
        $c = $c + 1;
        echo "{$c}<br>";
    }
}
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 method

trait StaticExample{
    public static function doSomething(){
        return &#39;Doing something.&#39;;
    }
}
class Example{
    use StaticExample;
}
Example::doSomething();

Output result: Doing something.

Attributes

Trait can also define attributes.

Example #11 Defining attributes

trait PropertiesTrait{
    public $x = 1;
}
class PropertiesExample{
    use PropertiesTrait;
}
$example = new PropertiesExample;
$example->x;

If a trait defines an attribute, the class will not be able to define an attribute with the same name, otherwise an error will be generated. If the property's definition in the class is compatible with its definition in the trait (same visibility and initial value) the error level is E_STRICT, otherwise it is a fatal error.

Example #12 Conflict

trait PropertiesTrait{
    public $sname = true;
    public $different = false;
}
class PropertiesExample{
    use PropertiesTrait;
    public $sname = true; //Strict Standards
    public $different = true; //致命错误
}


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:php crawlerNext article:php crawler