菜单

PHP 5.4 new code reuse Trait detailed

2017年11月22日 - PHPer

Beginning with the 5.4.0 version of PHP, PHP provides a new concept of code reuse, that is, Trait. Trait literally means “properties” and “features”, and we can understand that using the Trait keyword can add new features to classes in PHP.

Familiar with object oriented software reuse, there are two ways of code reuse in software development: Inheritance and polymorphism. In PHP, only single inheritance can be achieved. And Trait avoided that. The following is illustrated by a simple frontal example.

1. inherit VS polymorphism VS Trait

Now there are two classes of Publish.php and Answer.php. To add LOG functionality to it, record actions inside the class. There are several solutions:

inherit

polymorphic

Trait

1.1. inheritance

As shown in fig.:

The code structure is as follows:

/ / Log.php

<? PHP

Class Log

{

(publicfunctionstartLog)

{

/ / echo…

}

 

(publicfunctionendLog)

{

/ / echo…

}

}

/ / Publish.php

<? PHP

Class PublishextendsLog

{

 

}

/ / Answer.php

<? PHP

Class AnswerextendsLog

{

  

}

It can be seen that inheritance really meets the requirements. But it’s against the object oriented principle. The relationship between Log (Publish) and answer (Answer) is not the relationship between the subclass and the parent class. So this is not recommended.

1.2. polymorphism

As shown in fig.:

Implementation code:

/ / Log.php

<? PHP

Interface Log

{

(publicfunctionstartLog);

(publicfunctionendLog);

}

/ / Publish.php

<? PHP

Class PublishimplementsLog

{

(publicfunctionstartLog)

{

Implement (method.) startLog / TODO:

}

(publicfunctionendLog)

{

Implement (method.) endLog / TODO:

}

}

/ / Answer.php

<? PHP

Class AnswerimplementsLog

{

(publicfunctionstartLog)

{

Implement (method.) startLog / TODO:

}

(publicfunctionendLog)

{

Implement (method.) endLog / TODO:

}

}

Log operations should be all the same, so it’s the same for Publish and Answer. Obviously, it goes against the DRY (Don’t Repeat Yourself) principle. So this is not recommended.

1.3. Trait

As shown in fig.:

The code is as follows:

/ / Log.php

<? PHP

Trait Log{

(publicfunctionstartLog) {

/ / echo.

}

(publicfunctionendLog) {

/ / echo.

}

}

/ / Publish.php

<? PHP

ClassPublish {

UseLog;

}

$publish=newPublish ();

$publish-> startLog ();

$publish-> endLog ();

/ / Answer.php

<? PHP

ClassAnswer {

UseLog;

}

$answer=newAnswer ();

$answer-> startLog ();

$answer-> endLog ();

As you can see, we’ve implemented code reuse without adding code complexity.

1.4. conclusion

Although the way of inheritance can solve the problem, but the idea is contrary to the object oriented principle, appears very rough; polymorphic way is feasible, but does not conform to the DRY principle in software development, increases the maintenance cost. The Trait method avoids the above shortcomings and implements the code reuse more gracefully.

The scope of 2. Trait

Understanding the benefits of Trait, we also need to understand the rules in its implementation, first of all, the scope of action. This is better proof, the implementation code is as follows:

<? PHP

ClassPublish {

UseLog;

(publicfunctiondoPublish) {

($this-> publicF);

($this-> protectF);

($this-> privateF);

}

}

$publish=newPublish ();

$publish-> doPublish ();

The output of the code is as follows:

Publicfunction

Protectedfunction

Privatefunction

It can be found that the scope of Trait is visible within the reference of the Trait class. Can be understood as the use keyword, the Trait implementation code Copy to a reference to the class of the Trait.

Priority of attributes in 3. Trait

When it comes to priorities, you have to have a contrasting reference, where the reference object refers to the class of Trait and its parent class.

Prove the priority of attributes in Trait applications through the following code:

<? PHP

Trait Log

{

(publicfunctionpublicF)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

(protectedfunctionprotectF)

{

Echo__METHOD__.’protected function’. PHP_EOL;

}

}

 

ClassQuestion

{

(publicfunctionpublicF)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

(protectedfunctionprotectF)

{

Echo__METHOD__.’protected function’. PHP_EOL;

}

}

 

ClassPublishextendsQuestion

{

UseLog;

 

(publicfunctionpublicF)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

(publicfunctiondoPublish)

{

($this-> publicF);

($this-> protectF);

}

}

$publish=newPublish ();

$publish-> doPublish ();

The output of the code is as follows:

Publish:: publicFpublicfunction

Log:: protectFprotectedfunction

Through the example above, we can conclude that the priority of Trait application is as follows:

A method that covers the trait from the current class

Trait covers inherited methods

Class member priority is: current class > Trait> parent class

4. Insteadof and As keywords

In a class, you can refer to multiple Trait, as follows:

<? PHP

Trait Log

{

(publicfunctionstartLog)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

(protectedfunctionendLog)

{

Echo__METHOD__.’protected function’. PHP_EOL;

}

}

 

Trait Check

{

{publicfunctionparameterCheck ($parameters)

/ do sth

}

}

 

ClassPublishextendsQuestion

{

UseLog, Check;

{publicfunctiondoPublish ($para)

($this-> startLog);

$this-> parameterCheck ($para);

($this-> endLog);

}

}

In this way, we can refer to multiple Trait in a class. When you refer to multiple Trait, it is easy to have a problem. The most common problem is how to use the same name attribute or method in the two Trait. At this time, you need to use the two key words Insteadof and as. Please see the following implementation code:

<? PHP

 

Trait Log

{

PublicfunctionparameterCheck ($parameters)

{

Echo__METHOD__.’parameter check’.$parameters. PHP_EOL;

}

 

(publicfunctionstartLog)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

}

 

Trait Check

{

PublicfunctionparameterCheck ($parameters)

{

Echo__METHOD__.’parameter check’.$parameters. PHP_EOL;

}

 

(publicfunctionstartLog)

{

Echo__METHOD__.’public function’. PHP_EOL;

}

}

 

ClassPublish

{

{useCheck, Log

Check:: parameterCheck insteadof Log;

Log:: startLog insteadof Check;

: startLogascsl Check;

}

 

(publicfunctiondoPublish)

{

($this-> startLog);

$this-> parameterCheck (‘params’);

($this-> CSL);

}

}

 

$publish=newPublish ();

$publish-> doPublish ();

Execute the above code and output the following:

Log:: startLogpublicfunction

Check:: parameterCheck parameter checkparams

Check:: startLogpublicfunction

As literal meaning, the insteadof keyword replaces the latter with the former, and the as keyword starts replacing the method

发表评论

电子邮件地址不会被公开。