Médio PHP
Conflito entre traits
Enunciado
Crie duas traits: A com método falar() que retorna "A" e B com método falar() que retorna "B". Crie a classe C que usa ambas as traits, resolve o conflito usando insteadof para preferir o método de A e cria um alias falarB para o método de B. Instancie C e imprima o retorno de falar() e falarB() em linhas separadas.
Requisitos
- As traits
AeBdevem ter o métodofalar(). - A classe
Cdeve usaruse A, B { ... }cominsteadofeas. - O método
falar()deve retornarAefalarB()deve retornarB. - A saída deve ter duas linhas:
AeB.
Código inicial
<?php
// Defina as traits A e B e a classe C
$c = new C();
echo $c->falar() . "\n";
echo $c->falarB() . "\n";
Saída esperada
A
B
Ver dica
A sintaxe é use A, B { A::falar insteadof B; B::falar as falarB; } dentro da classe.
Mostrar solução
<?php
trait A {
public function falar(): string {
return "A";
}
}
trait B {
public function falar(): string {
return "B";
}
}
class C {
use A, B {
// Usa o método falar() da trait A no lugar do da trait B
A::falar insteadof B;
// Cria um alias falarB() para o método falar() da trait B
B::falar as falarB;
}
}
$c = new C();
echo $c->falar() . "\n";
echo $c->falarB() . "\n";
Passo a passo
- Definimos a trait
Acomfalar()retornando"A". - Definimos a trait
Bcomfalar()retornando"B". - Na classe
C, usamosuse A, B { ... }para importar ambas. - Dentro das chaves,
A::falar insteadof B;resolve o conflito: o métodofalar()da traitAé o que será usado na classe. B::falar as falarB;cria um aliasfalarBque aponta para o métodofalar()da traitB.- Instanciamos
Ce chamamosfalar()(retornaA) efalarB()(retornaB).
Por que funciona
Quando duas traits trazem métodos com o mesmo nome, o PHP não sabe qual usar e emite erro fatal. insteadof diz explicitamente qual método deve prevalecer, e as permite manter o outro método acessível sob um novo nome. Isso dá controle total sobre a composição de comportamentos.
Erros comuns
- Esquecer o
insteadof:use A, B;gera erro fatal "Trait method falar has not been applied, because there are collisions". - Usar
asseminsteadofquando há conflito: o erro persiste, pois o alias não resolve a colisão. - Colocar
use A, B { ... }fora da classe: a sintaxe de resolução só é válida dentro da classe.
Outra forma de resolver
Se você não precisa dos dois métodos, basta use A; e ignorar B. Ou, se quiser renomear ambos:
use A, B {
A::falar as falarA;
B::falar as falarB;
}
Isso é útil quando nenhum dos nomes originais deve ser mantido.
Saída esperada
A
B