浅谈 PHP 中的 Trait 关键字

由于 PHP 是单继承语言,因此使用 trait 来实现了类似多继承的代码复用,一个 trait 和一个类相似,但 trait 不能像类一个实例化,而是通过关键字use添加到其它类的内部,相比于传统继承方法,trait 增加了水平特性的组合。

引入了 trait 类的调用顺序依次为:当前类 ==> trait ==> 父类。

在 trait 中,可以使用抽象方法、静态变量与静态方法,在 trait 中同样可以定义属性。

如果在引入的不同 trait 中包含了同名方法,则需要使用 insteadof 关键字或as关键字来避免冲突,前者是声明排除掉其它方法,后者则是对冲突的方法名重命名,与命名空间中的as作用相同,建议使用as关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?php
class Base
{
public function hello() {
echo 'method hello from class Base';
}
}

trait Hello
{
public function hello()
{
echo 'method hello from Trait Hello!';
}

public function hi()
{
echo 'method hi from Trait Hello!';
}

abstract public function getValue();

public static function staticMethod()
{
echo 'static method staticMethod from Trait Hello!';
}

public function staticValue()
{
static $value;
$value++;
echo $value;
}
}

trait Hi
{
public function hello() {
echo 'method hello from Trait Hi!';
}

public function hi() {
echo 'method hi from Trait Hi!';
}
}

trait HelloHi
{
use Hello, Hi {
Hello::hello insteadOf Hi; // 注意是 insteadOf 关键字,不是 instanceof,害我纳闷儿了半天
Hi::hi insteadOf Hello;
}
}

class MyNew extends Base
{
use HelloHi;

private $value = 'class MyNew';
public function getValue() {
return $this->value;
}
}

$obj = new MyNew();
$obj->hello(); // method hello from Trait Hello!
$obj->hi(); // method hi from Trait Hi!
MyNew::staticMethod(); // static method staticMethod from Trait Hello!
echo $obj->getValue(); // class MyNew
$objOther = new MyNew();
$obj->staticValue(); // 1
$objOther->staticValue(); // 2,因为 $value 是静态变量,所以结果会进行累加

参考资料

  1. Trait - PHP Manual
  2. Laravel 框架关键技术解析 3.6 节
因为热爱,所以执着。