什么是性状
第一次听说这东东,在《modern PHP》一书中看到,感觉在某些时候非常有用。
性状是php5.4.0引入的新概念,即像类又像接口,但是又不是类也不是接口,它是类的部分实现,能把模块化的实现方式注入多个无关的类当中,促进代码的重用。
为什么要用性状
例如RetailStore和Car这两个PHP类,这两个类在继承的层次结构中没有共同的父类,但是都能使用地理编码技术转换成经纬度,然后在地图中显示,要怎么设计呢?
第一反应是创建一个父类Geocodable,让RetailStore和Car这两个类继承这个类,但是这种解决办法不好,因为我们强制让两个无关的类去继承同一个祖先,就像是非让两个不认识的人认同一个爹一样。
第二反应是创建Geocodable接口,定义实现地理编码功能需要哪些方法,然后让这两个类去实现接口,这种方法好一点,让每个类都能包邮自然的继承层次结构,不过我们要在两个类中重复实现相同的地理编码功能,这不符合DRY(Don’t Repeat Yourself)原则。
好了,要出大招了,用性状来解决,创建一个Gecodable性状,在性状中定义并实现地理编码功能的方法,然后在RetailStore和Car类中混入这个性状,这么做不会搅乱这两个类原本的继承层次结构。
如何创建性状
<?php
trait Gecodable{
//这里是性状的实现
/**@var string**/
protected $address;
protected $geocoder;
protected $geocoderResult;
public function setGeocoder($geocoder){
$this->geocoder = $geocoder;
}
public function setAddress($address){
$this->address = $address;
}
public function setGeocoderResult($geocoderResult){
$this->geocoderResult = $geocoderResult;
}
public function getLatitude(){
return $this->geocoderResult->getLatitude();
}
}
用关键字trait,里面的实现跟类一样。
如何使用性状
使用很简单,把user MyTrait;语句驾到php类的定义体中就可以,看下面示例:
<?php
class RetailStore{
use Geocodable;
//下面是类的其他实现
}
就这么简单,然后就可以把性状中的属性和方法当成RetailSotre的属性方法来用,调用方法跟调用RetailStore中的属性方法一样。
<?php $geocoder = ''; $store = new RetailStore(); $store->setAddress('xxx'); $store->setGeocoder($geocoder); $latitude = $store->getLatitude();
警告:PHP解释器在编译时会把性状复制黏贴到类的定义体中国年,但是不会处理这个操作引入的不兼容问题,如果性状假定类中有特定的属性或方法(在性状中没定义),要确保相应的类中有对应的属性方法