什么是性状?
性状是在PHP5.4.0引入的新概念,既像类又像接口。
性状是类的部分实现(即常量,属性和方法),可以混入一个或多个现有的PHP类中。
作用:
1. 表明类可以做什么(像是接口)
2. 提供模块化实现(像是类)
PHP是一种面向对象语言,使用的是典型的继承模型。在继承模型中,我们通过先编写一个通用的根类,实现基本功能,然后扩展这个类,创建更具体的类,从直接父类继承实现。
为什么使用性状(也就是性状产生的原因)?
在大多数时候,通过使用继承就可以解决大部分的问题。但是,如果让两个毫不相关的类具有类似的行为,应该怎么做呢?
例如:
现在有两个类,一个是汽车类(Car)和手机类(Phone)。
这两个类的作用十分不同,而且在继承层次结构关系中没有共同的父类。
不过,这两个类都应该能使用地理位置(GPS)技术转换成经纬度,然后显示在地图上。
性状就是为了解决这种问题而诞生的。性状能把模块化的实现方式注入多个无关的类中。而且性状还能够促进代码重用。
为了解决上述,第一反应,就是通过编一个GPS基类,让汽车类(Car)和手机类(Phone)都继承GPS类。
但是,这种做法非常不好,强制让两个毫不相关的类继承同一个父类(祖先)。
第二反应,创建一个GPS接口,定义实现地理位置功能需要的方法,然后让汽车类和手机类都实现这个接口,这种做法比较好的地方,是每个类都能保持原有的继承结构。
但是,违反了DRY原则,需要在每个实现类中写入相同的与地理位置相关功能的代码。
接下来,可以通过性状来实现上述问题。
// 创建GPS性状 trait GPS { protected $address; protected $geocoderResult; public function setAddress($address) { $this->address = $address; } public function getLatitude() { if (isset($this->geocoderResult) === false) { $this->geocodeAddress(); } } public function geocodeAddress() { $this->geocoderResult = $this->geocoder->geocode($this->address); } public function getLongitude() { if (isset($this->geocoderResult) === false) { return $this->geocodeAddress(); } return $this->geocoderResult->getLongitude(); } }
GPS性状中,只实现与地理位置相关的功能,除此之外什么都不需要。
// 性状的使用 class Car { use GPS; // TODO 类的具体实现 } class Phone { use GPS; // TODO 类的具体实现 } 建议:命名空间和性状都使用use关键字导入,可是导入的位置有所不同。命名空间,类,接口,函数和常量在类的定义体外导入。 而性状在类的定义体内导入。