雨燕 - CnSwift

敏捷开发- agile development

PHP中的Trait使用介绍

PHP是单继承语言,为了使开发人员在不同层次结构内独立的类中复用方法,PHP5.4.0起,PHP实现了一种代码复用的方法Trait,Trait无法自身实例化,通过和Class组合的方式实现多继承。

  • 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
trait A {
public function sayHello() {
echo "Hello\n";
}
}

class B {
public function sayWorld() {
echo "World\n";
}
}

class C extends B {
use A;
public function sayHi() {
echo "Hi\n";
}
}

$c = new C();
$c->sayHi();
$c->sayHello();
$c->sayWorld();
  • 优先级 派生类>trait>基类
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
trait A {
public function sayHello() {
echo "Hello trait\n";
}

public function sayHi() {
echo "Hi trait\n";
}
}

class B {
public function sayHello() {
echo "Hello class\n";
}

public function sayHi() {
echo "Hi class\n";
}
}

class C extends B {
use A;
public function sayHello() {
echo "Hello C\n";
}
}

$c = new C();
$c->sayHello();
$c->sayHi();
  • 多个trait,用英文逗号分隔。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
trait Hello {
public function sayHello() {
echo "Hello ";
}
}

trait World {
public function sayWorld() {
echo "World";
}
}

class Test {
use Hello,World;
public function sayHelloWorld() {
echo "!\n";
}
}
$test = new Test();
$test->sayHello();
$test->sayWorld();
$test->sayHelloWorld();
  • 解决冲突
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
trait A {
public function sayHello() {
echo "Hello A\n";
}

public function sayHi() {
echo "Hi A\n";
}
}

trait B {
public function sayHello() {
echo "Hello B\n";
}

public function sayHi() {
echo "Hi B\n";
}
}

class C {
// 使用insteadof操作符明确指定使用冲突方法中的哪一个
use A,B {
A::sayHello insteadof B;
B::sayHi insteadof A;
}
}

class D {
use A,B {
A::sayHello insteadof B;
B::sayHi insteadof A;
A::sayHi as hi; // as操作符为某个方法引入别名,解决多个trait都插入一个同名方法的冲突
}
}

$c = new C();
$c->sayHello();
$c->sayHi();

echo "\n";

$d = new D();
$d->sayHello();
$d->sayHi();
$d->hi();
  • 使用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
trait Hello {
public function sayHello() {
echo "Hello trait\n";
}
}

class A {
use Hello {
Hello::sayHello as protected; // 使用as操作符修改sayHello的访问控制
}
}

class B {
use Hello {
Hello::sayHello as private sayHi; // 使用as操作符给sayHello引入一个别名并修改别名的访问控制,原版sayHello的访问控制不改变
}
}

$a = new A();
// PHP Fatal error: Uncaught Error: Call to protected method A::sayHello() from context '' in trait5.php:158
$a->sayHello();

$b = new B();
$b->sayHello();
// PHP Fatal error: Uncaught Error: Call to private method B::sayHi() from context '' in trait5.php:162
$b->sayHi();
  • 使用trait组合trait
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
trait Hello {
public function sayHello() {
echo "Hello ";
}
}

trait World {
public function sayWorld() {
echo "World!\n";
}
}

trait HelloWorld {
use Hello,World;
}

class Hi {
use HelloWorld;
}

$hi = new Hi();
$hi->sayHello();
$hi->sayWorld();
  • trait使用抽象方法,对组合trait的类施加强制要求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
trait Hello {
public function sayHello() {
echo "Hello " . $this->getWorld();
}
// 抽象方法
abstract public function getWorld();
}

class Hi {
private $world;
use Hello; // 组合trait
// 实现抽象方法
public function getWorld() {
return $this->world;
}
public function setWorld($val) {
$this->world = $val;
}
}

$hi = new Hi();
$hi->setWorld("world!\n");
$hi->sayHello();
  • trait定义静态属性和静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
trait Counter {
public function inc() {
// 静态属性
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
// 静态方法
public static function doSomething() {
return "Doing Something\n";
}
}

class Test {
use Counter;
}

$test = new Test();
$test->inc();
echo $test::doSomething();
$test->inc();
  • trait定义属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
trait A {
public $name = 'frank';
public $age = 18;
}

class B {
use A;
public $name = 'frank';
public $age = 28;
}

$b = new B();
echo $b->name; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
echo "\n";
echo $b->age; // PHP Fatal error: B and A define the same property ($age) in the composition of B. However, the definition differs and is considered incompatible. Class was composed in trait5.php on line 250
echo "\n";
感谢赞赏.

Welcome to my other publishing channels