Home >Backend Development >PHP Tutorial >[Modern PHP] Chapter 2 New Features Three Traits
Traits
Many of my PHP developer friends don’t know much about traits, which is a new concept introduced in PHP 5.4.0. Traits look like interfaces but work like classes, so what exactly are they? It's neither.
A trait has partial implementation (such as constants, properties and methods) that can be embedded into one or more actual PHP classes. Traits have two responsibilities: indicating what a class can do (similar to an interface); and providing a modular implementation (similar to a class).
You may already have some understanding of traits in other languages. For example, the functions of Ruby's modules and mixins are very similar to PHP's traits.
Why should we use traits
PHP language uses the classic inheritance model. This means that you start with a common root class that provides the basic implementation. From the root class, more specific classes are created that directly inherit the various implementations of the parent class. This is called an inheritance hierarchy, and many programming languages use this common pattern.
To make it easier to understand, imagine that you travel back in time to high school to study biology. Do you still remember the phylum, order, family, genus and species of the organisms you studied? There are six major realms in total. The realm is derived from the door, the phylum is derived from the class, the class is derived from the order, the order is derived from the family, the family is derived from the genus, and the genus is followed by the species. Each descent down the species hierarchy represents a specific characteristic.
The classic inheritance model works well in most cases. But what if there are two unrelated classes that need to implement similar behavior? For example, one PHP class is called RetailStore, and another PHP class is called Car. They can be said to be two completely unrelated classes, and they cannot share a common parent class in terms of inheritance relationship. However, both classes require the longitude and latitude from the geographic location to display map coordinates.
We created traits to solve this problem. They can inject partial implementation into unrelated classes. Traits also facilitate code reuse.
When I encounter this problem, my first solution (and the worst) is to create a public parent class Geocodable for the RetailStore and Car classes to inherit. This solution is really bad, because forcing two unrelated classes to share a common ancestor looks very awkward in their respective inheritance hierarchies.
My second solution (slightly better) is to create a Geocodable interface that defines what methods are needed to implement geolocation. Both RetialStore and Car classes can implement this Geocodable interface. It is indeed a good solution to allow each class to retain its natural inheritance relationship. But we still need to repeat the definition in the interface in each class, which is not a DRY solution.
DRY is the abbreviation of Do not repeat yourself. As a good programming practice, we should never repeat the same code in multiple places. There cannot be a situation where you have to passively modify the same code in other places because you have changed one piece of code.
My third solution (the best solution) is to construct a Geocodable trait and define and implement related methods in it. I can add Geocodable traits to the RetailStore class and Car class without disrupting the class inheritance hierarchy.
How to construct a trait
The following shows how to define a PHP trait:
<?php trait MyTrait { // 此处是trait的具体实现 }
Let’s go back to our Geocodable example to better demonstrate the use of traits. We all know that the RetailStore class and the Car class need to support the geographical positioning function, and we can all agree that inheritance and interfaces are not the best solution. Instead, we construct a Geocodable trait that returns a longitude and latitude coordinate that can be marked on the map. Example 2-12 shows our complete Geocodable trait.
Example 2-12 Definition of Geocodable trait
<span style="font-size:14px;"><?php trait Geocodable { /** @var string */ protected $address; /** @var \Geocoder\Geocoder */ protected $geocoder; /** @var \Geocoder\Result\Geocoded */ protected $geocoderResult; public function setGeocoder(\Geocoder\GeocoderInterface $geocoder) { $this->geocoder = $geocoder; } public function setAddress($address) { $this->address = $address; } public function getLatitude() { if (isset($this->geocoderResult) === false) { $this->geocodeAddress(); } return $this->geocoderResult->getLatitude(); } public function getLongitude() { if (isset($this->geocoderResult) === false) { $this->geocodeAddress(); } return $this->geocoderResult->getLongitude(); } protected function geocodeAddress() { $this->geocoderResult = $this->geocoder->geocode($this->address); return true; } }</span>
Our Geocodable trait defines properties of three classes:
To be continued...
The above introduces [Modern PHP] Chapter 2 New Features Three Traits, including aspects of the content. I hope it will be helpful to friends who are interested in PHP tutorials.