Конфликты с другими методами трейтов
Как мне справиться с трейты, у которых методы имеют одинаковые имена?
Я столкнулся с проблемой при использовании нескольких трейтов с методами, которые имеют одинаковые названия. Вот пример кода:
trait FooTrait {
public function fooMethod() {
return 'foo method';
}
public function getRow() {
return 'foo row';
}
}
trait TooTrait {
public function tooMethod() {
return 'too method';
}
public function getRow() {
return 'too row';
}
}
class Boo {
use FooTrait;
use TooTrait;
public function booMethod() {
return $this->fooMethod();
}
}
При попытке вызвать метод getRow()
в классе Boo
, я получаю ошибку:
Fatal error: Trait method getRow has not been applied, because there are collisions with other trait methods on Boo in...
Как мне с этим справиться?
Кроме того, как мне получить метод из trait FooTrait
?
$a = new Boo;
var_dump($a->getRow()); // Fatal error: Call to undefined method Boo::getRow() in...
Редактировать:
Теперь я изменил класс Boo
, чтобы явно указать, откуда брать метод getRow
:
class Boo {
use FooTrait, TooTrait {
FooTrait::getRow insteadof TooTrait;
}
public function booMethod() {
return $this->fooMethod();
}
}
Но если я также хочу получить метод getRow
из TooTrait
в классе Boo
, возможно ли это?
3 ответ(ов)
При возникновении конфликта между методами в Trait в PHP, возникает фатальная ошибка, если конфликт не разрешён явно. Чтобы разрешить конфликты имен в Trait, используемых в одном классе, необходимо использовать оператор insteadof
, который позволяет выбрать один из конфликтующих методов.
Поскольку этот оператор позволяет исключить только один метод, для включения одного из конфликтующих методов под другим именем можно использовать оператор 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 {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
В этом примере класс Talker
использует методы smallTalk
из Trait B и bigTalk
из Trait A. Класс Aliased_Talker
, в свою очередь, делает это же, но в дополнение использует реализацию bigTalk
из Trait B под другим псевдонимом talk
.
Пример кода, аналогичный вашему случаю, может выглядеть так:
class Boo {
use FooTrait, TooTrait {
FooTrait::getRow insteadof TooTrait;
}
public function booMethod() {
return $this->fooMethod();
}
}
Этот подход работает даже если вы разделяете операторы use
, но, на мой взгляд, более очевиден. Также можно использовать оператор as
для объявления алиаса.
Да, это возможно. Вы можете использовать что-то подобное:
class Boo {
use FooTrait, TooTrait {
FooTrait::getRow as getFooRow;
TooTrait::getRow as getTooRow;
}
public function getRow(...$arguments)
{
return ['foo' => $this->getFooRow(...$arguments), 'too' => $this->getTooRow(...$arguments)];
}
public function booMethod(...$arguments)
{
return $this->getFooRow(...$arguments);
}
}
В данном примере класс Boo
использует два трейта FooTrait
и TooTrait
. Методы getRow
обоих трейтов переименовываются в getFooRow
и getTooRow
соответственно, чтобы избежать конфликтов. Метод getRow
класса Boo
затем объединяет результаты обоих методов и возвращает их в виде массива. Метод booMethod
позволяет получить доступ только к значению из getFooRow
.
Если у вас простая ситуация, как в моем случае, вы можете создать трейт, который будет использовать другой трейт, что приведет к конфликту.
trait FooTrait {
// ...
public function fooMethod() {
return 'foo method';
}
// ...
}
trait MyFooTrait {
use FooTrait;
public function fooMethod() {
return 'my foo method';
}
}
class Boo
{
use MyFooTrait;
}
В вашем случае FooTrait
приходит из стороннего PHP-пакета, и вы хотите использовать его с улучшенными методами в нескольких классах вашего приложения. Таким образом, вы просто "перекрываете" метод fooMethod
в своем трейте MyFooTrait
, чтобы добавить свою реализацию. Этот подход позволит вам использовать функциональность из FooTrait
, а также адаптировать поведение для ваших нужд.
Функции startsWith() и endsWith() в PHP
Как получить расширение файла в PHP?
Как читать большой файл построчно?
ReCaptcha 2.0 с использованием AJAX
Почему нельзя вызывать абстрактные функции из абстрактных классов в PHP?