ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
| PHP中的Traits用法详解 | | | --- | --- | PHP是单继承的语言,在PHP 5.4 Traits出现之前,PHP的类无法同时从两个基类继承属性或方法。php的Traits和Go语言的组合功能有点类似, [TOC] 通过在类中使用use关键字声明要组合的Trait名称,而具体某个Trait的声明使用trait关键词,Trait不能直接实例化。具体用法请看下面的代码: ``` <?php namespace core\traits_class; //先创建一个特性类 trait Traits { public $names = 'traits'; public function traits() { return '特性类:' . $this->names; } } //创建一个父级类 class Base { protected $name = 'base'; public function base() { return '继承了一个父级类:' . $name; } } //子级类继承父级 Base 这个类 class Son extends Base { use Traits; //triat 特性类通过 use 直接引用继承 //实现 trait 特性类和父级 Base 类中的方法 public function son() { echo '父级类:' . $this->base(); echo '父级类:' . $this->traits(); } } ``` 上面的例子中 Son 类继承了 Base 类和通过引用继承 Traits 这个特性类,实现了双继承或者应该可以多继承 [TOC] 注意:当 Traits 特性类和父类 Base 中存在相同的方法或者属性名时,子类 Son 中的方法会覆盖 Trait 的 方法,而 Trait 的方法又覆盖了父类中的方法 [TOC] 如果要组合多个Trait,通过逗号分隔 Trait名称: ``` use Trait1, Trait2; ``` 如果多个Trait中包含同名方法或者属性时,会怎样呢?答案是当组合的多个Trait包含同名属性或者方法时,需要明确声明解决冲突,否则会产生一个致命错误。 ~~~ <?php 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; } //输出:Fatal error:  Trait method hello has not been applied, because there are collisions with other trait methods on Class1 in ~~~  使用insteadof和as操作符来解决冲突,insteadof是使用某个方法替代另一个,而as是给方法取一个别名,具体用法请看代码: ~~~ <?php 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(); ~~~ ~~~ Trait2::hello Trait1::hi Trait2::hello Trait1::hi Trait2::hi Trait1::hello ~~~ as关键词还有另外一个用途,那就是修改`方法`的访问控制: ~~~ <?php trait Hello { public function hello() { echo "hello,我是周伯通\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,我是周伯通,因为原来的hello方法仍然是公共的 $Obj2->hi(); # 报致命错误,因为别名hi方法被修改成私有的 ~~~ ~~~ Uncaught Error: Call to protected method Class1::hello() from context '' in D:\web\mytest\p.php:18 ~~~ Trait 也能组合Trait,Trait中支持抽象方法、静态属性及静态方法,测试代码如下: ~~~ <?php trait Hello { public function sayHello() { echo "Hello 我是周伯通\n"; } } trait World { use Hello; public function sayWorld() { echo "hello 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 'do you get World ?'; } } $Obj = new HelloWorld(); $Obj->sayHello(); $Obj->sayWorld(); echo $Obj->getWorld() . "\n"; HelloWorld::doSomething(); $Obj->inc(); $Obj->inc(); ~~~ ~~~ Hello 我是周伯通 hello world do you get World ? Doing something 1 2 ~~~