traits是php又一实现代码复用的方法,如abstract,interface。
给我的感觉就是php实现多继承的又一出路。
使用trait
trait的声明语法跟class几乎无异,然后在类中使用use语句来插入trait。Trait 无法像 Class 一样使用 new 实例化!
包含单个trait
trait A {
public function demo1() {
echo 'This is the demo1' . PHP_EOL;
}
}
class Base {
use A;
}
$obj = new Base();
$obj->demo1();
/*
输出:
This is the demo1
*/
包含多个trait
// trait A 同上
trait B {
public function demo2() {
echo 'This is the demo2' . PHP_EOL;
}
}
class Base {
use A, B;
}
$obj = new Base();
$obj->demo1();
$obj->demo2();
/*
输出:
This is the demo1
This is the demo2
*/
trait中包含trait
// trait A, B同上
trait C {
use A, B;
}
命名冲突
trait中的属性与当前类属性的命名冲突
当trait中的属性跟当前类的属性发生命名冲突时将产生错误,分有2种情况
+ 当两者的访问控制(public...)和初始值相同时,产生一个E_STRICT错误
+ 否则将产生 致命错误
如下,将产生一个致命错误(初始值不同)
trait A {
public $bool = true;
}
class Base {
use A;
public $bool;
}
$obj = new Base();
trait中的方法与基类中的方法的命名冲突
如果当前类是派生类,则trait会直接覆盖基类中的方法
如下
trait A {
public function say() {
echo 'This is traitA::say' . PHP_EOL;
}
}
class Base {
public function say() {
echo 'This is the Base::say' . PHP_EOL;
}
}
class ExBase {
use A;
}
$obj = new ExBase();
$obj->say();
/*
输出:
This is traitA::say
*/
trait中的方法与当前类方法的命名冲突
类方法将覆盖trait中的方法
// trait同上
class Base {
public function say() {
echo 'This is the Base::say' . PHP_EOL;
}
use A;
}
$obj = new Base();
$obj->say();
/*
输出:
This is the Base::say
*/
trait中的方法与trait中的方法的命名冲突
如果没有明确解决2个trait间的方法名的冲突的话,将产生一个致命错误
如下,将产生一个致命错误
trait A {
public $a;
public function demo1() {
echo 'This is traitA demo1' . PHP_EOL;
}
}
trait B {
public function demo1() {
echo 'This is traitB demo1' . PHP_EOL;
}
}
class Base {
use A, B;
}
- 使用insteadof
// trait A, B同上
class Base {
use A, B {
// 用A::demo1覆盖B中的同名方法
A::demo1 insteadof B;
}
}
- 再使用as
在使用insteadof后若想使用被覆盖的方法可使用as来别名引用
// trait A, B同上
class Base {
use A, B {
// 用A::demo1覆盖B中的同名方法
A::demo1 insteadof B;
B::demo1 as demoB;
}
}
$obj = new Base;
$obj->demo1();
$obj->demoB();
/*
输出:
This is traitA demo1
This is traitB demo1
*/
- as 的另一作用
使用 as 语法还可以用来调整方法的访问控制
如下,在访问demoB方法时将产生致命错误(试图访问一个private方法)
// trait A, B同上
class Base {
use A, B {
// 用A::demo1覆盖B中的同名方法
A::demo1 insteadof B;
B::demo1 as private demoB;
}
}
$obj = new Base;
$obj->demoB();
trait中抽象与静态
trait中的抽象
跟普通抽象相同,其作用及导致结果与普通abstract一样。
trait A {
public $a;
abstract public function say();
}
trait中的静态成员
trait中不能定义static属性,但在方法中可以
如下,同普通static变量
trait A {
public function say() {
static $cut = 1;
++$cut;
return $cut;
}
}
trait中的静态方法
同普通的静态方法
trait A {
public static function say() {
return 'This is a static function' . PHP_EOL;
}
}
class Base {
use A;
}
$obj = new Base;
echo Base::say();
echo $obj->say(); // php 5.3后支持
/*
输出
This is a static function
This is a static function
*/