Php 5.4 new code reuse Trait details, 5.4 trait
Starting from PHP 5.4.0, PHP provides a new concept of code reuse, that is, Trait. Trait literally means "Features" and "Features". We can understand that using the Trait keyword can add new features to classes in PHP.
Anyone familiar with object-oriented knowledge knows that common code reuse methods in software development include inheritance and polymorphism. In PHP, only single inheritance is allowed. Trait avoids this. The following is a simple example of comparison.
1. Inheritance VS polymorphism VS Trait
Now you havePublish.php
AndAnswer.php
These two classes. You need to add the LOG function to record internal actions of the class. There are several solutions:
- Inheritance
- Polymorphism
- Trait
1.1. Inheritance
:
The code structure is as follows:
// Log.php<?phpClass Log{ public function startLog() { // echo ... } public function endLog() { // echo ... }}
// Publish.php<?phpClass Publish extends Log{}
// Answer.php<?phpClass Answer extends Log{ }
We can see that inheritance does meet the requirements. However, this violates the object-oriented principle. The relationship between operations such as Publish and Answer and logs is not the relationship between sub-classes and parent classes. Therefore, this is not recommended.
1.2. Polymorphism
:
Implementation Code:
// Log.php<?phpInterface Log{ public function startLog(); public function endLog();}
// Publish.php<?phpClass Publish implements Log{ public function startLog() { // TODO: Implement startLog() method. } public function endLog() { // TODO: Implement endLog() method. }}
// Answer.php<?phpClass Answer implements Log{ public function startLog() { // TODO: Implement startLog() method. } public function endLog() { // TODO: Implement endLog() method. }}
The operations for logging should be the same. Therefore, the implementation of logging in Publish and Answer actions is the same. Obviously, this violates the DRY (Don't Repeat Yourself) principle. Therefore, this implementation is not recommended.
1.3. Trait
:
The implementation code is as follows:
// Log.php<?phptrait Log{ public function startLog() { // echo .. } public function endLog() { // echo .. }}
// Publish.php<?phpclass Publish { use Log;}$publish = new Publish();$publish->startLog();$publish->endLog();
// Answer.php<?phpclass Answer { use Log;}$answer = new Answer();$answer->startLog();$answer->endLog();
We can see that code reuse is implemented without increasing the complexity of the Code.
1.4. Conclusion
Although the inheritance method can also solve the problem, its idea violates the object-oriented principle and seems very crude. The polymorphism method is also feasible, but it does not conform to the DRY principle in software development, increased maintenance costs. The Trait method avoids the above shortcomings and achieves code reuse elegantly.
2. Trait Scope
To understand the benefits of Trait, we also need to understand the rules in its implementation. Let's talk about the scope first. The implementation code is as follows:
<?phpclass Publish { use Log; public function doPublish() { $this->publicF(); $this->protectF(); $this->privateF(); }}$publish = new Publish();$publish->doPublish();
The output result is as follows:
public functionprotected functionprivate function
It can be found that the scope of Trait is visible within the reference of this Trait class. It can be understood that the use keyword copies the Trait implementation code to the class that references the Trait.
3. Priority of attributes in Trait
When it comes to priority, you must have a reference object for comparison. The reference object here references the Trait class and its parent class.
Use the following code to verify the priority of attributes in a Trait application:
<?phptrait Log{ public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() { echo __METHOD__ . ' protected function' . PHP_EOL; }}class Question{ public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function protectF() { echo __METHOD__ . ' protected function' . PHP_EOL; }}class Publish extends Question{ use Log; public function publicF() { echo __METHOD__ . ' public function' . PHP_EOL; } public function doPublish() { $this->publicF(); $this->protectF(); }}$publish = new Publish();$publish->doPublish();
The output result of the above Code is as follows:
Publish::publicF public functionLog::protectF protected function
Through the above example, we can sum up the priority of the Trait application as follows:
The member from the current class overwrites the trait method.
Trait overwrites the inherited method
The class member priority is:Current class> Trait> parent class
4. Insteadof and As keywords
You can reference multiple Trait instances in a class as follows:
<?phptrait Log{ public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; } protected function endLog() { echo __METHOD__ . ' protected function' . PHP_EOL; }}trait Check{ public function parameterCheck($parameters) { // do sth }}class Publish extends Question{ use Log,Check; public function doPublish($para) { $this->startLog(); $this->parameterCheck($para); $this->endLog(); }}
In the above method, we can reference multiple Trait instances in a class. When multiple Trait instances are referenced, problems may occur. The most common problem is that if two Trait instances have attributes or methods of the same name, what should they do? In this caseInsteadof
Andas
See the following implementation code for the two keywords:
<?phptrait Log{ public function parameterCheck($parameters) { echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL; } public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; }}trait Check{ public function parameterCheck($parameters) { echo __METHOD__ . ' parameter check' . $parameters . PHP_EOL; } public function startLog() { echo __METHOD__ . ' public function' . PHP_EOL; }}class Publish{ use Check, Log { Check::parameterCheck insteadof Log; Log::startLog insteadof Check; Check::startLog as csl; } public function doPublish() { $this->startLog(); $this->parameterCheck('params'); $this->csl(); }}$publish = new Publish();$publish->doPublish();
Run the above Code and the output result is as follows:
Log::startLog public functionCheck::parameterCheck parameter checkparamsCheck::startLog public function
Just as literally,insteadof
The former replaces the latter with the keyword,as
Keyword indicates an alias for the replaced method.
When referencing Trait, the use keyword is used, and the use keyword is also used to reference the namespace. The difference between the two is that Trait is used inside the class when being referenced.