PHP的类是单一继承模式,也就是每个类只能继承一个父类(基类)。
但有时需要引入更多通用(共用)的方法,同时这些方法又不适合集成到基类。
那么这时,就需要使用其他方法来引入这些方法。其中trait,就是方法之一。
trait是PHP5.4之后出现的一种代码复用方法,形式和Class非常相似,同时可以随意组合任意引入。
trait一般在当前类和其同父类(基类)的其他类都需要使用相同方法时,而其父类(基类)又要尽量避免出现这些方法时使用。
甚至有时可能其他关联不是特别大的类(分别继承不同的父类)也可能会使用共同的方法,也可以使用trait的方法。
尽量通俗一点的说一下trait:
trait像类,但不是类,不可以直接使用new关键字创建对象;简单理解是用类的形式,封装一大堆通用(共用)的方法,供其他类引用。
trait和use搭配使用。定义好trait后,“use trait定义的名字;”,就可以直接使用里边定义的一切了,是不是很简单?很方便?
现在知道了trait,接下来就通过代码实例,演示一下trait的具体使用和一些小情况。
一、trait的使用
代码:
// trait trait traitTest { public function test() { echo "trait test...\n"; } } // 父类 class ParentClass { public function parent() { echo "parent...\n"; } } // 子类 class SubClass extends ParentClass { use traitTest; public function sub() { echo "sub...\n"; } } $obj = new SubClass; $obj->sub();// 调用子类方法 $obj->parent();// 调用父类的方法 $obj->test();// 调用trait里的方法
代码和结果截图:
上边的这个例子,子类直接extentds父类,然后又在类内use了trait。这样当前类(子类)就拥有了这三个的全部方法。
子类的sub方法,父类的parent方法,trait的test方法,在子类内都可以直接调用使用。
最基础的使用就这些,看起来是不是也不算难?甚至感觉挺简单的?
那么我们进一步思考一下,类的“继承”难免会出现同名方法,那么这三个里边如果有同名方法,最终会保留哪个?谁的方法会被覆盖呢?
二、当父类、子类和trait的方法重名
代码:
// trait trait traitTest { public function test() { echo "trait test...\n"; } public function lookClassName() { echo "trait here\n"; echo __CLASS__ . "\n"; } } // 父类 class ParentClass { public function parent() { echo "parent...\n"; } public function lookClassName() { echo __CLASS__ . "\n"; } } // 子类 class SubClass extends ParentClass { use traitTest; public function sub() { echo "sub...\n"; } public function lookClassName() { echo __CLASS__ . "\n"; } } $obj = new SubClass; $obj->sub();// 调用子类方法 $obj->parent();// 调用父类的方法 $obj->test();// 调用trait里的方法 $obj->lookClassName();// 调用同名方法
代码和结果截图:
上边这段例子的结果很明显的发现,最终当前类(子类)的方法被调用了,也就是三个里边都有同名方法时,当前类的方法优先。
接下来,注释(删除)当前类的lookClassName()方法。
看上边截图,很明显了,当子类(当前类)没有同名方法,只有父类(基类)和trait中的方法同名时,trait中的方法优先。
结论:当前类(子类)、trait和父类(基类)中有同名方法时“子类高于trait高于父类”。子类的方法会覆盖trait中的方法,而trait的方法会覆盖父类的方法。
前边有提到,trait可以随意组合,随意引用,那么是不是可以同时引入多个trait呢?是。在一个类内,可以同时use多个trait。
三、类内同时引入多个trait
// trait trait traitTest { public function test() { echo "trait test...\n"; } public function lookClassName() { echo "trait here\n"; echo __CLASS__ . "\n"; } } trait traitTest2 { public function test2() { echo "trait2 test...\n"; } public function lookClassName() { echo "trait2 here\n"; echo __CLASS__ . "\n"; } } trait traitTest3 { public function test3() { echo "trait3 test...\n"; } public function lookClassName() { echo "trait3 here\n"; echo __CLASS__ . "\n"; } } // 父类 class ParentClass { public function parent() { echo "parent...\n"; } public function lookClassName() { echo __CLASS__ . "\n"; } } // 子类 class SubClass extends ParentClass { use traitTest; use traitTest2, traitTest3; public function sub() { echo "sub...\n"; } public function lookClassName() { echo __CLASS__ . "\n"; } } $obj = new SubClass; $obj->sub();// 调用子类方法 $obj->parent();//