Разрешение конфликтов в трейтах
Так как один класс может использовать несколько трейтов, то нас может поджидать проблема, возникающая тогда, когда два трейта имеют одноименные методы.
В этом случае 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
, возвращающий
сумму результатов методов подключенных трейтов.