7.9 Trait

2017-07-01  本文已影响10人  57fc17b7d598

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();
上一篇 下一篇

猜你喜欢

热点阅读