什么是Trait?:
1. php 从 5.4版本起开始支持 Trait 特性,和 Class 类很相似,类中一般的特性 Trait 都可以实现。Trait 不是用来替代类的,而是要去 “ 混入” 类中。
2. Trait 是为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。 Trait 和类组合的语义是定义了一种方式来减少复杂性,避免传统多继承相关的典型问题。
3.例如,需要同时继承两个抽象类,这是php语言不支持的功能, Trait 就是为了解决这个问题。或者可以理解为在继承类链中隔离了子类继承父类的某些特性,相当于要用父类的特性的时候,如果有 Trait 就优先调用 Trait 的成员。
Trait 的声明
声明 Trait 当然也要使用 trait 关键字了, 类有的特性 Trait 一般都有。 Trait 支持 final、static 和 abstract 等修饰词,所以 Trait 也就支持抽象方法的使用、类定义静态方法,当然也可以定义属性。但 Trait 无法如类一样使用 new 实例化,因为 Trait 就是用来混入类中使用的,不能单独使用。如果拿 Interface 和 Trait 类比, Trait 会有更多方便的地方。
简单的 Trait 的声明代码如下所示:
//使用 trait 关键字申明一个 Trait,需要php5.4以上的版本
trait dome{
public $a = true; //声明成员属性
static $b = 1; //使用 static 关键字声明静态变量
function method1(){
} //声明成员方法
abstract public function method2(); //加入抽象修饰符,说明调用类必须实现它
}
Trait 的基本使用
Trait 不能通过它自身来实例化对象,必须将其混入类中使用。相当于将 Trait 中的成员复制到类中,在应用类时就像使用自己的成员一样。如果要在类中使用 Trait 。需要通过 use 关键字将 Trait 混入类中。
简单的 Trait 的基本使用代码如下所示:
//使用 trait 关键字申明一个 Trait,有两个成员方法
trait dome{
function method1(){
} //声明成员方法
function method2(){
} //声明成员方法
}
class dome1{ //申明一个类,类中混入 Trait
use dome; //使用 use 关键字在类中使用 dome
}
$obj = new dome1(); //实例化 dome1 对象
$obj->method1(); //通过dome1对象,直接调用混入类dome1的成员方法 method1
$obj->method2(); //通过dome1对象,直接调用混入类dome1的成员方法 method2
Trait 应该了解如下的重点
1. Trait 会覆盖调用类的父类方法。
-
从基类继承的成员被 Trait 插入的成员所覆盖。优先顺序是:来自当前类的成员覆盖了 Trait 的方法,而 Trait 则覆盖了被继承的方法。
-
Trait 不能像类一样使用 new 实例化对象。
-
单个 Trait 可由多个 Trait 组成。
-
在单个类中,用 use 引入 Trait ,可以引入多个。
-
Trait 支持修饰词,例如 final、static、abstract。
-
可以使用 insteadof 及 as 操作符解决 Trait之间的冲突。
-
使用 as 语法还可以用来调整方法的访问控制。
使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,
trait Trait1 {
public function hello() {
echo "Trait1::hello\n";
}
public function hi() {
echo "Trait1::hi\n";
}
}
trait Trait2 {
public function hello() {
echo "Trait2::hello\n";
}
public function hi() {
echo "Trait2::hi\n";
}
}
class Class1 {
use Trait1, Trait2 {
Trait2::hello insteadof Trait1;
Trait1::hi insteadof Trait2;
}
}
class Class2 {
use Trait1, Trait2 {
Trait2::hello insteadof Trait1;
Trait1::hi insteadof Trait2;
Trait2::hi as hei;
Trait1::hello as hehe;
}
}
$Obj1 = new Class1();
$Obj1->hello();
$Obj1->hi();
echo "\n";
$Obj2 = new Class2();
$Obj2->hello();
$Obj2->hi();
$Obj2->hei();
$Obj2->hehe();
Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下:
trait Hello {
public function sayHello() {
echo "Hello\n";
}
}
trait World {
use Hello;
public function sayWorld() {
echo "World\n"
abstract public function getWorld()
public function inc()
static $c = 0
$c = $c + 1
echo "$c\n"
public static function doSomething() {
echo "Doing something\n";
}
}
class HelloWorld {
use World;
public function getWorld() {
return 'get World';
}
}
$Obj = new HelloWorld();
$Obj->sayHello();
$Obj->sayWorld();
echo $Obj->getWorld() . "\n";
HelloWorld::doSomething();
$Obj->inc();
$Obj->inc();
as关键词还有另外一个用途,那就是修改 方法 的访问控制:
trait Hello {
public function hello() {
echo "hello,trait\n";
}
}
class Class1 {
use Hello { hello as protected; }
}
class Class2 {
use Hello { Hello::hello as private hi; }
}
$Obj1 = new Class1();
$Obj1->hello(); # 报致命错误,因为hello方法被修改成受保护的
$Obj2 = new Class2();
$Obj2->hello(); # 原来的hello方法仍然是公共的
$Obj2->hi(); # 报致命错误,因为别名hi方法被修改成私有的