PHP中Trait特性

@date:2016-03-27 19:02:00

Trait是自 PHP 5.4.0 起添加的一个新特性,是 PHP 多重继承的一种解决方案。例如,需要同时继承两个 Abstract Class, 这将会是件很麻烦的事情,Trait 就是为了解决这个问题。

下面是一个例子,类Demo同时继承了Test1Test2

<?php
trait Test1{
    public function add($a, $b){
        echo $a + $b;
    }
}

trait Test2{
    public function sub($a, $b){
        echo $a - $b;
    }
}

class Demo{
    use Test1,Test2;
}

$obj = new Demo();
$obj->add(3, 5); // 8

$obj->sub(3, 5); // -2


一些特性 #

1、优先级:当前类 > trait > 基类 。 即当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。
2、多个 trait: 通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。
3、冲突的解决:
如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。
为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。
以上方式仅允许排除掉其它方法,as 操作符可以将其中一个冲突的方法以另一个名称来引入。

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>

4、trait嵌套:Trait 之间也可以相互的嵌套:在 trait 定义时通过使用一个或多个 trait,它能够组合其它 trait 中的部分或全部成员。
5、Trait 的抽象方法:我们可以在 Trait 中声明需要实现的抽象方法,这样能使使用它的 Class 必须实现它。

需要注意的几点 #

Trait 会覆盖调用类继承的父类方法
Trait 无法如 Class 一样使用 new 实例化
单个 Trait 可由多个 Trait 组成
在单个 Class 中,可以使用多个 Trait
Trait 支持修饰词(modifiers),例如 final、static、abstract
我们能使用 insteadof 以及 as 操作符解决 Trait 之间的冲突

一些看法 #

坦白讲,第一眼看到 Trait 对它并没有任何好感。PHP5 以来带来的新特性已经足够得多,而且让开发者们有点应接不暇。

同时,Trait 更像是程序员的“语法糖”,然而它提供便利的同时可能会造成巨大的隐患。

针对类中已经实现的方法,Trait 没有效果。

探讨 #

那么 Trait 的出现是为何呢?有网友的回答比较有意思,但不无道理:

因为php没有javascript作用域链的机制,所以无法把function bind到class里面,曾经以为php 5.3的闭包可以做这个事,最后才发觉作用域的设计不允许这么干。

参考:
1、PHP: Traits - Manual
http://php.net/manual/zh/language.oop5.traits.php
2、PHP 5.4 的 Trait 特性Web开发酷勤网
http://www.kuqin.com/web/20111119/315048.html

Build by Loppo 0.6.14