trait
是PHP为类只能单继承而实现的代码复用机制。
trait
不能继承,也不能实现接口。
trait
不能有常量。
trait
不能实例化。
trait
中可以使用 trait
。
trait
中可以使用抽象方法。
trait
中通过 insteadof
来解决命名冲突,也可以使用 as
来设置别名和访问级别。
trait
中的优先级为 自己 > trait
> 父类。
trait
和类中如果有同名的属性,那么需要保证他们的访问级别和值相同才不会报错。
一个简单的 trait
例子
// trait
trait One{
// 普通属性
public $name = 'One';
// 不能有常量
// 静态属性
static $desc = 'Hello One';
// 普通方法
public function say(){
echo $this->name . ': <br />';
echo static::$desc . '<br />';
}
}
// 类
class Foobar{
// 引入 trait,可以引入多个,用逗号分开
use One;
// 构造函数
public function __construct(){
// 调用trait 中的函数
$this->say();
}
}
// 实例化
new Foobar();
当子类继承了父类,同时引入了 trait
,三者中如果有同名的成员(属性、方法),那么优先级从大到小是 自己 > trait
> 父类。
// trait
trait One{
public function fn(){
echo "One::fn";
}
}
// parent
class Two{
public function fn(){
echo "Two::fn";
}
}
// class
class Foobar extends Two{
use One;
public function fn(){
echo "Foobar::fn";
}
}
// 实例化 输出:Foobar::fn
(new Foobar())->fn();
当一个类使用了多个trait
时,难免会发生 trait
之间会有命名冲突的问题,如果不解决,会报错。
// trait
trait One{
public function foo(){
echo "One::foo <br />";
}
public function bar(){
echo "One::bar <br />";
}
}
trait Two{
public function foo(){
echo "Two::foo <br />";
}
public function bar(){
echo "Two::bar <br />";
}
}
trait Three{
public function foo(){
echo "Three::foo <br />";
}
public function bar(){
echo "Three::bar <br />";
}
}
// class
class Four{
// 引入 trait
use One, Two, Three {
// 当 One 中的 foo方法 存在冲突时,排除掉 Two和Three 中的方法
One::foo insteadof Two, Three;
// 当 Two 中的 bar方法 存在冲突时,排除掉 One和Three 中的方法
Two::bar insteadof One, Three;
// 还一种方式是给方法起个别名
Three::foo as tf;
}
public function call(){
$this->foo();
$this->bar();
$this->tf();
}
}
// 实例化
(new Four())->call();
/*
最终输出
One::foo
Two::bar
Three::foo
*/
当一个 trait
中的方法访问级别较低时,可以通过 as
给它重新设置访问级别
// trait
trait One{
// 我是私有的,只能在类中使用,无法通过实例访问
private function say(){
echo "private <br />";
}
}
// 类
class Foobar{
use One {
// 调整方法的访问控制级别
say as public;
}
}
// 实例化
(new Foobar())->say();
可以给 trait
添加抽象方法来强制要求使用者必须做一些事。
// trait
trait One{
public function fn1(){
return $this;
}
// 我是抽象方法
public abstract function fn2();
}
// 类
class Foobar{
use One;
// 必须要实现抽象方法
public function fn2(){
echo "hello world";
}
}
// 实例化
(new Foobar())->fn1()->fn2();