In the Reading YII2 source code when the contact with the trait, I learned a bit, write down the blog record.
Since PHP 5.4.0, PHP implements a code reuse method, called traits.
Traits is a code reuse mechanism prepared for a single inheritance language similar to PHP. Trait to reduce the limitations of single inheritance languages, developers are free to 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 multiple inheritance and mixed-Class (Mixin).
Trait is similar to a class, but is intended only to combine functionality in fine-grained and consistent ways. Trait cannot be instantiated by itself. It adds a combination of horizontal attributes for traditional inheritance, which means that members of the application class do not need to inherit.
Trait sample
Copy Code code as follows:
<?php
Trait Ezcreflectionreturninfo {
function Getreturntype () {/*1*/}
function Getreturndescription () {/*2*/}
}
Class Ezcreflectionmethod extends Reflectionmethod {
Use Ezcreflectionreturninfo;
/* ... */
}
Class Ezcreflectionfunction extends Reflectionfunction {
Use Ezcreflectionreturninfo;
/* ... */
}
?>
Priority level
A member inherited from a base class is overwritten by a member that is trait inserted. Precedence is the method from which the members of the current class override the trait, while trait overrides the inherited method.
Example of precedence order
Copy Code code as follows:
<?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 ();
?>
The above routine will output: Hello world!
The member inherited from the base class is overwritten by the SayHello method in the inserted Sayworld Trait. Its behavior is consistent with the methods defined in the Myhelloworld class. The precedence is that the method in the current class overrides the trait method, while the trait method overrides the method in the base class.
Another example of priority order
Copy Code code as follows:
<?php
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 routine will output: Hello universe!
Multiple trait
Separated by commas, multiple trait are listed in a use declaration and can be inserted into a class.
Examples of the use of multiple trait
Copy Code code as follows:
<?php
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 ();
?>
The above routine will output: Hello world!
Resolution of the conflict
If two trait inserts a method with the same name, a fatal error will occur if the conflict is not explicitly resolved.
To resolve a naming conflict for multiple trait in the same class, you need to explicitly specify which of the conflicting methods to use using the INSTEADOF operator.
The above method only allows other methods to be excluded, and the as operator can introduce one of the conflicting methods to another name.
Examples of conflict resolution
Copy Code code as follows:
<?php
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;
}
}
?>
In this case, talker uses trait A and B. Because A and B have conflicting methods, it defines the use of smallTalk in trait B and the bigtalk in trait a.
Aliased_talker uses the as operator to define talk as the Bigtalk alias for B.
Modify access control for a method
You can also use the as syntax to adjust access control for a method.
Example of modifying access control for a method
Copy Code code as follows:
<?php
Trait HelloWorld {
Public Function SayHello () {
Echo ' Hello world! ';
}
}
Modify access control for SayHello
Class MyClass1 {
Use HelloWorld {SayHello as protected;}
}
Give the method a change to the alias of the access control
The original SayHello's access control was not changed.
Class MyClass2 {
Use HelloWorld {SayHello as Private Myprivatehello;}
}
?>
From trait to form trait
Just as a class can use trait, other trait can also use trait. When trait is defined, it can combine some or all of the members of other trait by using one or more trait.
From trait to form the trait example
Copy Code code as follows:
<?php
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 ();
?>
The above routine will output: Hello world!
Abstract members of the Trait
Trait supports the use of abstract methods in order to impose mandatory requirements on classes used.
Represents an example of a mandatory requirement by an abstract method
Copy Code code as follows:
<?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;
}
}
?>
Static members of the Trait
Traits can be defined by static member static methods.
Examples of static variables
Copy Code code as follows:
<?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
?>
Examples of static methods
Copy Code code as follows:
<?php
Trait Staticexample {
public static function DoSomething () {
Return ' doing something ';
}
}
Class Example {
Use Staticexample;
}
Example::d osomething ();
?>
Examples of static variables and static methods
Copy Code code as follows:
<?php
Trait Counter {
public static $c = 0;
public static Function Inc () {
Self:: $c = self:: $c + 1;
echo Self:: $c. "\ n";
}
}
Class C1 {
Use Counter;
}
Class C2 {
Use Counter;
}
C1::inc (); Echo 1
C2::inc (); Echo 1
?>
Property
Trait can also define attributes.
Example of defining a property
Copy Code code as follows:
<?php
Trait Propertiestrait {
public $x = 1;
}
Class Propertiesexample {
Use propertiestrait;
}
$example = new Propertiesexample;
$example->x;
?>
If trait defines a property, that class will not be able to define an attribute of the same name, or an error will occur. If the definition of the property in the class is compatible with the definition in trait (same visibility and initial value) the error level is e_strict, or it is a fatal error.
Examples of conflicts
Copy Code code as follows:
<?php
Trait Propertiestrait {
Public $same = true;
Public $different = false;
}
Class Propertiesexample {
Use propertiestrait;
Public $same = true; Strict Standards
Public $different = true; Fatal error
}
?>
Use of different
Examples of different use
Copy Code code as follows:
<?php
namespace Foo\bar;
Use Foo\test; means \foo\test-the initial \ is optional
?>
<?php
namespace Foo\bar;
Class SomeClass {
Use Foo\test; Means \foo\bar\foo\test
}
?>
The first use is used for namespace using Foo\test, the \foo\test is found, the second uses is a trait, and \foo\bar\foo\test is found.
__class__ and __trait__
__CLASS__ returns the use trait CLASS name,__trait__ returns trait name
Example below
Copy Code code as follows:
<?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
Trait single case
Examples are as follows
Copy Code code as follows:
<?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;
Calling the Trait method
Although not obvious, if the trait method can be defined as a static method in the normal class, it can be invoked
Examples are as follows
Copy Code code as follows:
<?php
Trait Foo {
function Bar () {
return ' Baz ';
}
}
Echo Foo::bar (), "\\n";
?>
Small Partners for traits new features are familiar with it, I hope this article can help.