PHP中的trait
PHP中的trait
一、前言
自PHP 5.4.0起,PHP 实现了代码复用的一个方法,称为 trait。trait其字面意思是"特性"、"特点"。使用Trait关键字,可以为PHP中的类添加新的特性。
trait 是一种为类似 PHP 的单继承语言而准备的代码复用机制。在PHP中,只能实现单继承,而trait则避免了这点。
PHP中的traits可以理解为一组能被不同的类都能调用到的方法集合,但Traits不是类!不能被实例化。
二、实现代码
1)trait 定义方法
Log.php
Publish.php
Answer.php
2)trait 定义属性
1 <?php 2 trait PropertiesTrait { 3 public $same = true; 4 public $different = false; 5 } 6 7 class PropertiesExample { 8 use PropertiesTrait; 9 public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒 10 public $different = true; // 致命错误 11 }
注意:
在 PHP 7.0 之前,在类里定义和 trait 同名的属性,哪怕是完全兼容的也会抛出 E_STRICT(完全兼容的意思:具有相同的访问可见性、初始默认值)。
3)多个trait
通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
1 <?php 2 trait Hello { 3 public function sayHello() { 4 echo 'Hello '; 5 } 6 } 7 8 trait World { 9 public function sayWorld() { 10 echo 'World'; 11 } 12 } 13 14 class MyHelloWorld { 15 use Hello, World; 16 public function sayExclamationMark() { 17 echo '!'; 18 } 19 } 20 21 $o = new MyHelloWorld(); 22 $o->sayHello(); 23 $o->sayWorld(); 24 $o->sayExclamationMark();
冲突的解决:
如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。
1 <?php 2 trait A { 3 public function smallTalk() { 4 echo 'a'; 5 } 6 public function bigTalk() { 7 echo 'A'; 8 } 9 } 10 11 trait B { 12 public function smallTalk() { 13 echo 'b'; 14 } 15 public function bigTalk() { 16 echo 'B'; 17 } 18 } 19 20 class Talker { 21 use A, B { 22 B::smallTalk insteadof A; 23 A::bigTalk insteadof B; 24 } 25 } 26 27 class Aliased_Talker { 28 use A, B { 29 B::smallTalk insteadof A; 30 A::bigTalk insteadof B; 31 B::bigTalk as talk; 32 } 33 }
三、优先级
Trait应用中的优先级如下:
1)来自当前类的成员覆盖了 trait 的方法
2)trait 覆盖了被继承的方法
总结:类成员优先级为: 当前类>Trait>父类
四、总结
继承的方式虽然也能解决问题,但其思路违背了面向对象的原则,显得很粗暴;多态方式也可行,但不符合软件开发中的DRY(Don't Repeat Yourself)原则,增加了维护成本。而Trait方式则避免了上述的不足之处,相对优雅的实现了代码的复用。
参考链接:
https://segmentfault.com/a/1190000008009455#item-1-3
https://www.php.net/manual/zh/language.oop5.traits.php