PHP5.4实现了一种代码复用的方法称为Trait。Trait为了减少单继承语言的限制,能够自由地在不同层次结构内独立的类中复用方法,Trait和Class组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。无法通过 trait 自身来实例化。一个类要应用trait需要使用use关键字,一个类可以应用多个trait,只需要在use关键字后用逗号分隔多个trait。trait中也可以应用其他的trait。
<?php
trait a{
function getA(){
return "a";
}
}
trait b{
function getB(){
return "b";
}
}
class Test{
use a,b;
}
$test=new Test();
echo $test->getA()."\n";
echo $test->getB()."\n";
trait c{
use a,b;
}
class Test2{
use c;
}
$test=new Test2();
echo $test->getA()."\n";
echo $test->getB()."\n";
?>
如果trait和class中存在相同的成员,则优先级规则为,当前类的成员->trait的成员->继承的成员。
<?php
trait a{
function getA(){
parent::getA();
echo "a in trait\n";
}
}
class Base{
function getA(){
echo "a in Base\n";
}
}
class Test extends Base{
use a;
}
class Test2 extends Base{
use a;
function getA(){
echo "a in Test2\n";
}
}
$test=new Test();
$test->getA();
$test2=new Test2();
$test2->getA();
?>
在应用多个trait时,如果插入了同名的方法,则需要解决冲突,否则会产生致命错误。解决冲突可以使用insteadof关键字来指明使用哪一个方法。还可以通过as关键字为某个方法引入别名,as关键字还可以调整方法的访问控制。
<?php
trait A {
public function printLower() {
echo 'a';
}
public function printUpper() {
echo 'A';
}
}
trait B {
public function printLower() {
echo 'b';
}
public function printUpper() {
echo 'B';
}
public function testAccess(){
}
}
class Test {
use A, B {
B::printLower insteadof A;
A::printUpper insteadof B;
B::printUpper as private upper;
testAccess as protected;
}
}
$test=new Test();
$test->printLower();
$test->printUpper();
//$test->upper();
//$test->testAccess();
?>
trait还支持抽象方法,应用trait的类需要实现抽象方法,否则会产生致命错误。trait还支持静态成员。
<?php
trait a{
function lower(){
return "a";
}
abstract function upper();
public static function foo(){
echo "static function foo\n";
}
}
class Test{
use a;
function upper(){
return "A";
}
}
$t=new Test();
echo $t->lower()."\n";
echo $t->upper()."\n";
Test::foo();
?>
trait中可以定义属性,但是应用trait的类不能定义与之同名的属性,否则会产生致命错误,除非属性是兼容的,即访问控制和初始默认值都相同。PHP7.0之前即使属性兼容也会有E_STRICT的提醒。
<?php
trait a{
public $var="a";
public $diff1="a";
public $diff2="a";
}
class Test{
use a;
public $var="a";
//public $diff1="b";
//protected $diff2="a";
}
?>