When it comes to code reuse in php, we may think of inheritance at the first time, but if there are too many subclasses derived from this single inheritance language, a series of problems will arise, such as dependence on parent classes, too much coupling, and destruction of class encapsulation. So is there a better way to achieve code reuse?
Since PHP 5.4.0, PHP has implemented another method of code reuse called traits.
Traits is a code reuse mechanism for a single inheritance language similar to PHP. In order to reduce the limitation of single inheritance language, Trait enables developers to freely reuse method sets in separate classes within different hierarchies. The semantics of Traits and class combinations define a way to reduce complexity and avoid typical problems associated with traditional multi-inheritance and Mixin classes.
Basic usage method
The use of Traits is very simple, just use the use keyword in the class.
trait A { public function test() { echo 'trait A::test()'; } } class b { use A; } $b=new b(); $b->test();
priority
Simply put, the Trait priority is higher than the parent method, but smaller than the current class method.
trait A { public function test() { echo 'trait A::test()'; } public function test1() { echo 'trait A::test1()'; } } class base{ public function test(){ echo 'base::test()'; } public function test1(){ echo 'base::test1()'; } } class b extends base{ use A; public function test(){ echo 'b::test()'; } } $b=new b(); $b->test();//b::test() $b->test1();//trait A::test1()
Trait conflict problem
When multiple Trait s are used, conflicts occur if the same method name exists among them. Using insteadof and as to resolve method name conflicts
insteadof can declare the use of a specific method in two identical method names.
trait A { public function test() { echo 'trait A::test()'; } } trait B { public function test() { echo 'trait B::test()'; } } class c{ use A,B{ A::test insteadof B;//Use insteadof to specify which method to use B::test as testB;//Modifying another method name with as requires that insteadof be used for post-conflict resolution } } $c=new c(); $c->test();//trait A::test() $c->testB();//trait B::test()
Method access control
Using the as keyword, we can modify the access rights of the trait method
trait A { public function test() { echo 'trait A::test()'; } private function test1(){ echo 'trait A::test1()'; } } class b{ use A{ test as protected; test1 as public test2;//You can also change the name when changing permissions } } $b=new b(); $b->test();//Fatal error: Call to protected method b::test() $b->test2();//trait A::test1()
Trait nested usage
trait A { public function test1() { echo 'test1'; } } trait B { public function test2() { echo 'test2'; } } trait C { use A,B; } class D { use C; } $d = new D(); $d->test2(); //test2
Definitions of variables, attributes, methods
Trait defines attributes, but cannot define attributes of the same name in a class
trait A { public $test1; } class B { use A; public $test; public $test1;//Strict Standards: B and A define the same property ($test1) in the composition of B... }
Trait supports Abstract methods, static methods and cannot directly define static variables, but static variables can be referenced by trait methods.
trait A { public function test1() { static $a = 0; $a++; echo $a; } abstract public function test2(); //Definitible abstract method } class B { use A; public function test2() { } } $b = new B(); $b->test1(); //1 $b->test1(); //2
Contrast javascript
This kind of trait use is similar to call in javascript in that it loads one object from another into the execution environment of the current object. Of course, javascript is a prototype-based language. Neither is comparable. It's just that there's little difference in the way it's used, and it's helpful to understand.
function a() { this.name="a"; this.getName=function(){ console.log(this.name); } } function b(){ this.name="b"; a.call(this); } var b = new b(); b.getName();//a
Because the variable environment in javascript is function-based, it outputs a