众所周知,PHP Java 都是 单继承 语言,就是一个子类只有一个父类,优点是避免了多继承情况下,可能造成对基类中某成员的访问出现的二义性问题,就是两个父类都有同一个成员方法不知道选哪个,C++的多继承通过作用域运算符::进行了限定,但是不太方便,也不应该把父类显示在对象调用里。
PHP 5.4.0 起 吸取了Python对多继承的处理,实现了一种 代码复用 的方法,称为 Trait。
我在写 tab选项卡 时发现了这个新特性,个人感觉非常好用。
如上图,每个界面是一个Action,不同控制器之间需要跳转,原来是把跳转方法写在各个Action里,这样会有很多重复的,显得很长,使用 Trait 以后就很方便了。
首先建立一个 Trait 文件。
<?php
trait PlaceMenu {
/**
* 基本信息
*/
public function doPlaceBase()
{
// 设置跳转session值
$id = SessionData::getPageData(MODULE_NAME, 'id');
SessionData::setPageData(PageConst::PlaceBase, 'id', $id);
// 跳转
$this->doRedirect(PageConst::PlaceBase);
}
/**
* 发货信息
*/
public function doPlaceTransport()
{
// 设置跳转session值
$id = SessionData::getPageData(MODULE_NAME, 'id');
SessionData::setPageData(PageConst::PlaceTransport, 'id', $id);
// 跳转
$this->doRedirect(PageConst::PlaceTransport);
}
}
然后在每个Action里使用 use 关键字,声明要组合的Trait。
<?php
import('PlaceMenu',APP_PATH.'Modules/Data/Action');
/**
* PlaceMedicineAction
*/
class PlaceMedicineAction extends BaseProjectAction
{
//顶部菜单
use PlaceMenu;
}
这样就把跳转方法“继承”到Action里了,使用注意以下几点。
1.Trait 不能实例化。
2 同一个类可以通过逗号分隔,在 use 声明中引入 多个 Trait。
3 当 Trait 定义了属性后,当前类就不能定义同样名称的属性,会抛出 E_STRICT。
4 优先级 当前类的方法 > Trait 的方法 > 父类的方法。
5 引入两个Trait 都有同名的方法或属性,会产生一个错误,需要使用 insteadof 操作符来明确指定,
或者用 as 操作符另起别名,还可以用来调整方法的访问控制。
<?php
trait A {
public function smallWord() {
echo 'a';
}
public function bigWord() {
echo 'A';
}
}
trait B {
public function smallWord() {
echo 'b';
}
public function bigWord() {
echo 'B';
}
}
class Writer {
use A, B {
B::smallWord insteadof A; //指定使用B的smallWord()
A::bigWord insteadof B; //指定使用A的bigWord()
B::bigWord as word; //给B的smallWord()指定别名
}
}
6 Trait 可以 use 其他 Trait,也可以使用抽象方法,静态属性,静态方法,规则和类一样。