Resolución de conflictos de Traits
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 53 de 91.
Cuando dos traits definen métodos con el mismo nombre, PHP lanza un error fatal. Debes indicarle explícitamente a PHP cómo manejar este conflicto utilizando los operadores insteadof y as.
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred");
$app->logToDatabase("Error occurred");
Salida:
File: Error occurred
DB: Error occurredEl operador insteadof elige qué método del trait usar cuando hay un conflicto. En este ejemplo, FileLogger::log gana y se convierte en el método log() por defecto. El operador as crea un alias, permitiéndote acceder al método del otro trait bajo un nombre diferente.
También puedes usar as para cambiar la visibilidad de un método:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
Esto hace que sayHello() sea privado dentro de la clase Person, aunque sea público en el trait. La resolución de conflictos te brinda un control detallado sobre cómo los métodos del trait se integran en tus clases.
Desafío
FácilVamos a construir un sistema de notificación donde diferentes canales pueden enviar mensajes, pero necesitamos resolver conflictos cuando múltiples traits proporcionan el mismo nombre de método.
Organizarás tu código en cuatro archivos:
EmailNotifier.php— Crea un trait llamadoEmailNotifiercon un métodonotify(string $message)que devuelva"Email: $message".SmsNotifier.php— Crea un trait llamadoSmsNotifiercon un métodonotify(string $message)que devuelva"SMS: $message".AlertService.php— Crea una claseAlertServiceque use ambos traits. Dado que ambos traits tienen un métodonotify(), deberás resolver este conflicto:- Usa
EmailNotifier::notifycomo el métodonotify()por defecto - Crea un alias
notifyBySmspara el métodoSmsNotifier::notify
notifyAll(string $message)que llame a ambos métodos de notificación y los devuelva combinados en líneas separadas.- Usa
main.php— Incluye todos los archivos necesarios y crea una instancia deAlertService. Recibirás una entrada: una cadena de mensaje. Imprime tres líneas:- El resultado de llamar a
notify()con el mensaje - El resultado de llamar a
notifyBySms()con el mensaje - El resultado de llamar a
notifyAll()con el mensaje
- El resultado de llamar a
Esto demuestra cómo insteadof resuelve qué método del trait prevalece cuando hay un conflicto de nombres, mientras que as te permite mantener el acceso al método del otro trait bajo un nombre diferente.
Hoja de referencia
Cuando múltiples traits definen métodos con el mismo nombre, PHP requiere una resolución de conflictos explícita utilizando los operadores insteadof y as.
El operador insteadof selecciona qué método del trait se utilizará por defecto:
<?php
trait FileLogger {
public function log(string $message): void {
echo "File: $message";
}
}
trait DatabaseLogger {
public function log(string $message): void {
echo "DB: $message";
}
}
class Application {
use FileLogger, DatabaseLogger {
FileLogger::log insteadof DatabaseLogger;
DatabaseLogger::log as logToDatabase;
}
}
$app = new Application();
$app->log("Error occurred"); // File: Error occurred
$app->logToDatabase("Error occurred"); // DB: Error occurred
El operador as crea un alias para un método de un trait, permitiendo el acceso bajo un nombre diferente.
También puedes usar as para cambiar la visibilidad del método:
<?php
trait Greeting {
public function sayHello(): void {
echo "Hello!";
}
}
class Person {
use Greeting {
sayHello as private;
}
}
Pruébalo tú mismo
<?php
require_once 'AlertService.php';
// Leer entrada
$message = trim(fgets(STDIN));
// TODO: Crear una instancia de AlertService
// TODO: Imprimir el resultado de llamar a notify() con el mensaje
// TODO: Imprimir el resultado de llamar a notifyBySms() con el mensaje
// TODO: Imprimir el resultado de llamar a notifyAll() con el mensaje
?>Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy