代码复用(Trait)

官方文档

  • trait 主要用于解决单继承引起的代码复用问题;

  • 在类中使用 trait 类似于include一个公用文件;

  • trait 支持所有修饰符例如 final,static,abstract

  • trait 不能通过 new 实例化;

  • trait 中的方法冲突可通过 insteadof 或 as 关键词解决。通过 as 还可修改访问权限。

优先顺序示例

从基类继承的成员被插入的 SayWorld Trait 中的 MyHelloWorld 方法所覆盖。其行为 MyHelloWorld 类中定义的方法一致。优先顺序是当前类中的方法会覆盖 trait 方法,而 trait 方法又覆盖了基类中的方法。

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
?>

多个 trait示例:通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。

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

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

以上例程会输出:

Hello World!

trait中使用trait的示例

正如 class 能够使用 trait 一样,其它 trait 也能够使用 trait。在 trait 定义时通过使用一个或多个 trait,能够组合其它 trait 中的部分或全部成员。

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

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

以上例程会输出:

Hello World!

trait中方法冲突问题示例:

<?php
trait firstTrait {
    function sameMethodName() { echo "method in firstTrait\n"; }
}

trait secondTrait {
    function sameMethodName() { echo "method in secontTrait\n"; }
}

class firstClass {
    // 使用firstTrait中的sameMethodName()方法而不是用secondTrait中的。:
    use firstTrait, secondTrait {
        firstTrait::sameMethodName insteadof secondTrait;
    }
}

$obj = new firstClass();

$obj->sameMethodName(); // Print : method in firstTrait

另一种方式

<?php
trait firstTrait {
    function sameMethodName() { echo "method in firstTrait\n"; }
}

trait secondTrait {
    function sameMethodName() { echo "method in secontTrait\n"; }
}

class firstClass {
    use firstTrait, secondTrait {
        // 使用firstTrait中的sameMethodName()方法而不是用secondTrait中的。:
        firstTrait::sameMethodName insteadof secondTrait;
        // 使用secondTrait中的sameMethoName()方法但改名为 anotherMethodName():
        secondTrait::sameMethodName as public anotherMethodName;
    }
}

$obj = new firstClass();
$obj->sameMethodName(); 
$obj->anotherMethodName();

Last updated