php中的traits

traits是php又一实现代码复用的方法,如abstract,interface。 
给我的感觉就是php实现多继承的又一出路。

使用trait

trait的声明语法跟class几乎无异,然后在类中使用use语句来插入trait。Trait 无法像 Class 一样使用 new 实例化!

包含单个trait

trait A {
  public function demo1() {
    echo 'This is the demo1' . PHP_EOL;
  }
}

class Base {
  use A;
}

$obj = new Base();
$obj->demo1();
/*
输出:
This is the demo1
*/

包含多个trait

// trait A 同上 
trait B {
  public function demo2() {
    echo 'This is the demo2' . PHP_EOL;
  }
}
class Base {
  use A, B;
}

$obj = new Base();
$obj->demo1();
$obj->demo2();
/*
输出:
This is the demo1
This is the demo2
*/

trait中包含trait

// trait A, B同上
trait C {
  use A, B;
}

命名冲突

trait中的属性与当前类属性的命名冲突

当trait中的属性跟当前类的属性发生命名冲突时将产生错误,分有2种情况

+ 当两者的访问控制(public...)和初始值相同时,产生一个E_STRICT错误
+ 否则将产生 致命错误

如下,将产生一个致命错误(初始值不同)

trait A {
  public $bool = true;
}
class Base {
  use A;
  public $bool;
}
$obj = new Base();

trait中的方法与基类中的方法的命名冲突

如果当前类是派生类,则trait会直接覆盖基类中的方法 
如下

trait A {
  public function say() {
    echo 'This is traitA::say' . PHP_EOL;
  }
}
class Base {
  public function say() {
    echo 'This is the Base::say' . PHP_EOL;
  }
}
class ExBase {
  use A;
}

$obj = new ExBase();
$obj->say();
/*
输出:
This is traitA::say
*/

trait中的方法与当前类方法的命名冲突

类方法将覆盖trait中的方法

// trait同上
class Base {
  public function say() {
    echo 'This is the Base::say' . PHP_EOL;
  }
  use A;
}
$obj = new Base();
$obj->say();
/*
输出:
This is the Base::say
*/

trait中的方法与trait中的方法的命名冲突

如果没有明确解决2个trait间的方法名的冲突的话,将产生一个致命错误 
如下,将产生一个致命错误

trait A {
  public $a;
  public function demo1() {
    echo 'This is traitA demo1' . PHP_EOL;
  }
}
trait B {
  public function demo1() {
    echo 'This is traitB demo1' . PHP_EOL;
  }
}
class Base {
  use A, B;
}
  • 使用insteadof
// trait A, B同上
class Base {
  use A, B {
    // 用A::demo1覆盖B中的同名方法
    A::demo1 insteadof B;
  }
}
  • 再使用as 
    在使用insteadof后若想使用被覆盖的方法可使用as来别名引用
// trait A, B同上
class Base {
  use A, B {
    // 用A::demo1覆盖B中的同名方法
    A::demo1 insteadof B;
    B::demo1 as demoB;
  }
}
$obj = new Base;
$obj->demo1();
$obj->demoB();
/*
输出:
This is traitA demo1
This is traitB demo1
*/
  • as 的另一作用 
    使用 as 语法还可以用来调整方法的访问控制 
    如下,在访问demoB方法时将产生致命错误(试图访问一个private方法)
// trait A, B同上
class Base {
  use A, B {
    // 用A::demo1覆盖B中的同名方法
    A::demo1 insteadof B;
    B::demo1 as private demoB;
  }
}
$obj = new Base;
$obj->demoB();

trait中抽象与静态

trait中的抽象

跟普通抽象相同,其作用及导致结果与普通abstract一样。

trait A {
  public $a;
  abstract public function say();
}

trait中的静态成员

trait中不能定义static属性,但在方法中可以 
如下,同普通static变量

trait A {
  public function say() {
    static $cut = 1;
    ++$cut;
    return $cut;
  }
}

trait中的静态方法

同普通的静态方法

trait A {
  public static function say() {
    return 'This is a static function' . PHP_EOL;
  }
}
class Base {
  use A;
}
$obj = new Base;
echo Base::say();
echo $obj->say(); // php 5.3后支持
/*
输出
This is a static function
This is a static function
*/

参考资料

  • php官方手册 http://docs.php.net/manual/zh/language.oop5.traits.php
  • 关于trait的一个讨论 http://bbs.phpchina.com/thread-210870-1-1.html

你可能感兴趣的:(php,php,traits)