# 代码复用(Trait)

[官方文档](http://php.net/manual/zh/language.oop5.traits.php)

* trait 主要用于解决单继承引起的代码复用问题；
* 在类中使用 trait 类似于include一个公用文件；
* trait 支持所有修饰符例如 final，static，abstract
* trait 不能通过 new 实例化；
* trait 中的方法冲突可通过 insteadof 或 as 关键词解决。通过 as 还可修改访问权限。

**优先顺序示例**

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

```php
<?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示例：**&#x901A;过逗号分隔，在 use 声明列出多个 trait，可以都插入到一个类中。

```php
<?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
<?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
<?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
<?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();
```
