参考php
引文php7
在php中,为实现代码复用,有了继承,可是一个类只能继承一个父类,不支持多继承,接口支持多实现,可是接口又不太同样,接口对外负责功能调用声明,不负责实现,由实现了接口的类去实现具体功能逻辑,严格意义上来讲,不算代码复用,从php5.4开始,php实现了另一种代码复用的方法,就是下文即将要说的trait。oop
traitthis
trait是为扩展相似php单继承的一种代码复用机制,解除单继承语言的限制,使开发人员可以自由地在不一样层次结构中组合复用method。trait自己不能实例化,它依托于class存在。传统继承是上下层面的关系,trait则为水平层面的组合。spa
优先级.net
对于相同方法名的方法而言,当前类的方法覆盖trait方法,trait中方法覆盖继承的父类方法3d
class Base { public function sayHello() { echo 'Hello '; } } trait SayWorld { public function sayHello() { parent::sayHello(); echo 'World!'; } public function sayPeter() { echo "\nhello trait peter\n"; } } class MyHelloWorld extends Base { use SayWorld; public function sayPeter() { echo "\nhello class peter\n"; } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayPeter();
输出code
多个traitblog
在类中,能够声明多个trait,将多个trait组合到一个类中继承
trait Hello { public function sayHello() { echo 'Hello '; } } trait World { public function sayWorld() { echo 'World'; } } class MyHelloWorld { use Hello, World; public function sayExclamationMark() { echo '!'; } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld(); $o->sayExclamationMark();
输出
trait冲突
若是trait之间定义了同名的方法,类中又组合了有同名方法的trait,会出现命名冲突,这个时候能够使用insteadof指明调用冲突方法中的某一个。trait中能够用as操做符为某个方法引入别名,注意引入别名并不会对原方法重命名,别名不能和已包含的trait中方法名重复
trait A { public function smallTalk() { echo 'a'; } public function bigTalk() { echo 'A'; } public function helloPeter() { echo "hello peter\n"; } } trait B { public function smallTalk() { echo 'b'; } public function bigTalk() { echo 'B'; } public function helloAlice() { echo "hello alice\n"; } } class Talker { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; } } class TalkerAs { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; B::bigTalk as talk; } } class TalkerHello { use A, B { B::smallTalk insteadof A; A::bigTalk insteadof B; // A::helloPeter as helloAlice; 别名不容许和已包含trait中方法重名 } } $talker = new Talker(); $talker->smallTalk(); $talker->bigTalk(); echo "\n"; $talkerAs = new TalkerAs(); $talkerAs->smallTalk(); $talkerAs->bigTalk(); $talkerAs->talk();
输出
trait组合trait
正如class能够使用多个trait,trait也能够使用trait
trait Hello { public function sayHello() { echo 'Hello '; } } trait World { public function sayWorld() { echo 'World!'; } } trait HelloWorld { use Hello, World; } class MyHelloWorld { use HelloWorld; } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld();
输出
抽象成员方法
在trait中能够定义抽象方法,类中若是要使用trait,必需要实现trait中的抽象方法
trait Hello { public function sayHelloWorld() { echo 'Hello ' . $this->getWorld() . "\n"; } abstract public function getWorld(); } class MyHelloWorld { private $world; use Hello; public function getWorld() { return $this->world; } public function setWorld($val) { $this->world = $val; } } $o = new MyHelloWorld(); $o->sayHelloWorld(); $o->setWorld('world'); $o->sayHelloWorld();
输出
属性
trait中也能够定义属性,但要注意trait定了某个属性后,使用该trait的类中就不能定义一样名称的属性,不然会产生fatal error。(属性若是是兼容的(一样的访问控制符和默认值),就不会产生fatal error,但在php7以前,会有E_STRICT提醒)
trait PropertiesTrait { public $same = true; public $different = false; } class PropertiesExample { use PropertiesTrait; public $same = true; // PHP 7.0.0 后没问题,以前版本是 E_STRICT 提醒 public $different = true; // 致命错误 }
php5.6
php7.1