# Разрешение конфликтов в трейтах

Так как один класс может использовать несколько трейтов, то нас может поджидать проблема, возникающая тогда, когда два трейта имеют одноименные методы.

В этом случае PHP выдаст фатальную ошибку. Чтобы поправить ситуацию, нужно будет разрешить конфликт имен явным образом. Как это делается - посмотрим на практике.

Пусть у нас есть два трейта с одинаковым методом `method`:

`<?php trait Trait1 { private function method() { return 1; } } trait Trait2 { private function method() { return 2; } } ?>`

Пусть у нас также есть класс `Test`, использующий оба наших трейта. Если просто подключить оба трейта к нашему классу, то PHP выдаст ошибку, так как у трейтов есть совпадающий методы:

`<?php // Данный код выдаст ошибку! class Test { use Trait1, Trait2; // подключаем трейты } ?>`

Давайте разрешим (в данном контексте это слово значит разрулим) конфликт имен наших трейтов. Для этого существует специальный оператор `insteadof` (переводится вместо чего-то). С помощью этого оператора будем использовать метод `method` трейта `Trait1` вместо такого же метода трейта `Trait2`:

`<?php class Test { use Trait1, Trait2 { Trait1::method insteadof Trait2; } } new Test; ?>`

Как вы видите, синтаксис тут следующий: вначале имя трейта, потом два двоеточия, потом имя метода, потом наш оператор `insteadof` и имя второго трейта.

Давайте проверим:

`<?php class Test { use Trait1, Trait2 { Trait1::method insteadof Trait2; } public function __construct() { echo $this->method(); // выведет 1, тк это метод первого трейта } } new Test; ?>`

Итак, в нашем классе мы сказали, что если используется метод `method`, то следует брать его из первого трейта. Можно и наоборот - взять метод второго трейта:

`<?php class Test { use Trait1, Trait2 { Trait2::method insteadof Trait1; } public function __construct() { echo $this->method(); // выведет 2, тк это метод второго трейта } } new Test; ?>`

В любом случае, если мы указываем использовать метод одного трейта, то метод второго трейта оказывается недоступным. Можно использовать и метод второго трейта, переименовав его через ключевое слово `as`, вот так:

`<?php class Test { use Trait1, Trait2 { Trait1::method insteadof Trait2; // берем метод из первого трейта Trait2::method as method2; // метод второго трейта будет доступен как method2 } public function __construct() { echo $this->method() + $this->method2(); // выведет 3 } } new Test; ?>`

При желании можно переименовать и метод первого трейта:

`<?php class Test { use Trait1, Trait2 { Trait1::method insteadof Trait2; Trait1::method as method1; // метод первого трейта будет доступен как method1 Trait2::method as method2; // метод второго трейта будет доступен как method2 } public function __construct() { echo $this->method1() + $this->method2(); // выведет 3 } } new Test; ?>`

Использовать ключевое слово `as` без определения главного метода через `insteadof` нельзя, это выдаст ошибку:

`<?php // Данный класс выдаст ошибку: class Test { use Trait1, Trait2 { Trait1::method as method1; Trait2::method as method2; } public function __construct() { echo $this->method1() + $this->method2(); } } new Test; ?>`

Сделайте `3` трейта с названиями `Trait1`, `Trait2` и `Trait3`. Пусть в первом трейте будет метод `method`, возвращающий `1`, во втором трейте - одноименный метод, возвращающий `2`, а в третьем трейте - одноименный метод, возвращающий `3`.

Сделайте класс `Test`, использующий все три созданных нами трейта. Сделайте в этом классе метод `getSum`, возвращающий сумму результатов методов подключенных трейтов.

←→
↑