声明:这是自PHP 5.4.0起,PHP实现的代码复用的新特性,称为traits,如果你现在用的版本比5.4.0低的话,请升级!
简单介绍:Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用方法集。Traits 和类组合的语义是定义了一种方式来减少复杂性,避免传统多继承和混入类(Mixin)相关的典型问题。
Trait 和一个类相似,但仅仅旨在用细粒度和一致的方式来组合功能。Trait 不能通过它自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用类的成员不需要继承。
举个栗子:
假设现在我们在开发一个站点,目前有很多不同的类:用户(User)、页面(Page)、联系表单(ContactForm)等。那么假如我们在开发该站点的时候,如果能够不去关心对象的类型,而可以使用一个调试工具函数来打印出一个给定的对象的信息,那将会十分有用:
有了这个需求,我们可能需要在每个类中添加这个方法的定义,巧妙的利用继承的话,我们可能仅仅需要在相对应的父类中定义该方法即可,但是这样的话还是会造成不必要的代码冗余(并且一旦对该方法的定义有所修改,就需要修改一大堆东西)。
通常情况下,当我们需要在多个不同的类中使用同一个方法的时候,继承就是一个不错的解决方案。然而在PHP中,每个类只能从单一的一个父类中继承,这样的话就不能为多个类指定同一个比较通用的父类了。你可能会想到接口,毕竟接口是多继承(实现)的,但是实现的时候还是要在子类中实现,代码冗余时没法避免的!
我们能不能这样想?假如现在有一个方法,当我想用的时候我就去用它,而不用管该对象是 User 还是 Page , 亦即不用管该对象是什么类型的。这时候 traits 就登场了。traits允许我们在不使用继承的情况下为一个类增加功能。
使用介绍:1、要创建一个 trait ,需要使用 trait 关键字,后面跟着它的名字和定义:
trait tSomeTrait { //Attributes function someFunction() { //实现代码 } }像一个抽象类或者一个接口一样,traits 是不能够被初始化的(就是说,我们不能从一个 trait 创建一个对象)。然而,我们可以通过使用 use 关键字在一个类的定义中为这个类增加一个 trait :
class someClass{ use tSomeTrait; public function func(){} }假如要包含多个 traits 时,就以逗号将其分隔开:
use trait1,trait2;就像在一个PHP脚本中使用 include 包含一个外部的PHP脚本就能使其马上生效一样,在这里增加一个 use TraitName 语句就能使这个 trait 的代码对当前类生效。
现在,当我们创建一个SomeClass 类型的对象的时候,这个对象就有了 someFunction() 方法:
$obj = new someClass(); $obj->someFunction();PS:接口与traits
traits 看上去和接口有很多地方十分相似,但是其实二者有着天壤之别。
一个接口会强制执行更严格的编程规则,以便类被设计成实现特定的方法。相反,一个 trait 使方法对一个类可用,记住是“可用”!即便它没有在类中定义。
接口中的规定的方法子类中必须要实现,代码冗余少不了么,但是用 trait 的话,代码只用写一遍,然后想怎么用怎么用。
抽象方法:假如在 traits 中使用抽象方法,那么必须在使用它的类中实现该方法!(这一点跟接口差不多):
trait tSomeTrait{ abstract function test(); } class cSomeClass{ use tSomeTrait; function test(){ echo "test"; } } 相互嵌套:traits 之间可以互相嵌套,类似于以下栗子:
trait trait1{ function func1(){ echo "func1"; } } //在trait2中使用trait1 trait trait2{ use trait1; function func2(){ echo "func2"; } } //此时的trait2中其实有两个方法:func1(),func2() class test{ use trait2; } $test = new test(); $test->func1(); $test->func2(); 优先级:如果在一个类中使用的trait中有一个方法和类中的一个方法同名,PHP就需要决定有限使用哪个方法:
如果方法是在一个类中定义的,那么它的优先级会比trait中 的方法的优先级高;
如果方法的定义是在父类中继承过来的,那么trait中方法的优先级高
不同traits冲突:假如在一个类中使用了 trait1、trait2 ,但是 trait1 和 trait2 中都定义 somgFunc() 方法,那么就会起冲突,如果不人为的解决了这个冲突,会导致错误。
为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof 操作符来明确指定使用冲突方法中的哪一个。