PHP 代码复用trait

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dgh_84/article/details/54749955

自PHP 5.4.0起,PHP实现了一种代码服用的方法,称为trait。

Trait是为类似PHP的单继承语言而准备的一种代码复用机制。Trait为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中服用 method。Trait和Class组合的语义定义了一种减少复杂性的方式,避免传统多继承和Mixin类相关典型问题。

Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。无法通过trait自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个Class之间不需要继承。

通过PHP文档的定义和解释,我们可以理解为 trait 是某个class 的一部分,它可以和任意class合并,但 trait 不能实例化,同时也不能被其它类继承;trait 本质上与class没有任何的关系,当某个class引用trait时,才会与当前class合并。

实例如下:

<?php

    trait SayWorld {
        public function sayHello(){
            echo 'world';
        }
    }

    class MyHelloWorld {
        //引入trait SayWorld 与 MyHelloWorld类合并
        use SayWorld;


    }
    //实例化类
    $hello = new MyHelloWorld;
    //输出 world
    $hello->sayHello();

需要注意的有以下几点:

  1. 优先级
    如果当前类中的方法名称与引入的trait 中的方法相同时,则当前类中的方法会覆盖trait 中的方法;如果当前类继承某个基类,而基类中的方法名称与trait 中的方法名称相同时,则引入的trait 中的方法会覆盖基类中的方法。

如下所示:

<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class TheWorldIsNotEnough {
    //引入HelloWorld与当前类TheWorldIsNotEnough合并
    use HelloWorld;
    //因为当前类与引入的HelloWorld中的方法重名,
    //所以当前类TheWorldIsNotEnough中的方法覆盖了HelloWorld中的方法sayHello
    public function sayHello() {
        echo 'Hello Universe!';
    }
}

$o = new TheWorldIsNotEnough();
//输出 Hello Universe!
$o->sayHello();
?>
  1. 冲突的解决

如果两个trait都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。

当多个trait 在同一个类中引入,且存在方法名称重复时,则需要使用insteadof操作符来明确指定重名方法是属于那个trait的;
还可以使用as操作符将其中一个方法重命名。

如下代码:

<?php
trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    //引入多个trait时,可以用逗号分割
    use A, B {
        //指定重名的方法分别属于那个trait
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker {
    use A, B {
        //指定重名的方法分别属于那个trait
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        //用as 操作符重命名trait中的重复方法
        B::bigTalk as talk;
    }
}
?>
  1. 修改方法的访问控制
    使用as操作符可以修改trait中方法的访问控制。
    如下所示:
<?php
trait HelloWorld {
    public function sayHello() {
        echo 'Hello World!';
    }
}

class MyClass1 {
    //修改 sayHello 的访问控制
    use HelloWorld { sayHello as protected; }
}

// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}
?>

对于在类中引入trait的其他操作访问,都与操作与同一个类中的方法、属性等相同。

注:trait 就相当于某一个class或者trait的一部分,在class与trait中引入某个trait时,会和当前引入的class或trait进行合并。

猜你喜欢

转载自blog.csdn.net/dgh_84/article/details/54749955
今日推荐