Traits frente a la herencia
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy. Lección 55 de 91.
Ahora que entiendes cómo funcionan los traits, aclaremos cuándo usar traits en lugar de herencia. Ambos permiten reutilizar código, pero sirven para propósitos diferentes y tienen características distintas.
La herencia establece una relación «es un». Una clase Dog que extiende Animal significa que un perro es un animal. La clase hija hereda la identidad de la clase padre y puede utilizarse en cualquier lugar donde se espere el tipo padre.
Los traits proporcionan una capacidad de «tiene un». Cuando una clase usa el trait Loggable, tiene funcionalidad de registro, pero no se convierte en un registrador. Los traits añaden comportamiento sin cambiar lo que la clase es fundamentalmente.
<?php
// Herencia: Dog ES un Animal
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// Trait: Dog TIENE capacidad de logging
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
Diferencias clave que debes recordar:
| Aspecto | Herencia | Traits |
|---|---|---|
| Relación | es-un | tiene una capacidad |
| Límite | Solo un padre | Se permiten múltiples traits |
| Comprobación de tipos | Funciona con instanceof | Sin identidad de tipo |
| Más adecuado para | Relaciones jerárquicas | Comportamientos compartidos entre clases no relacionadas |
Usa herencia cuando las clases compartan una identidad común. Usa traits cuando clases no relacionadas necesiten la misma funcionalidad sin formar parte del mismo árbol genealógico.
Desafío
FácilConstruyamos un sistema de vehículos que demuestre cuándo usar herencia en lugar de traits. Crearás una jerarquía de vehículos que comparten una identidad común mediante la herencia, mientras añades capacidades transversales mediante traits.
Organizarás tu código en cuatro archivos:
Trackable.php: Crea un trait llamadoTrackableque proporcione capacidad de seguimiento por GPS. El trait debe tener:- Una propiedad privada
$location(string) - Un método
setLocation(string $location)que almacene la ubicación actual - Un método
getLocation()que devuelva"Location: [location]"
- Una propiedad privada
Vehicle.php: Crea una clase baseVehicleque establezca la relación «es un». Incluye el archivo del trait. Usa la promoción de constructor para definir una propiedad protegida$brand. Añade un métododescribe()que devuelva"Vehicle: [brand]". Esta clase debe usar el traitTrackable, ya que todos los vehículos de nuestra flota tendrán GPS.Car.php: Crea una claseCarque extiendaVehicle. Incluye el archivo de Vehicle. Usa la promoción de constructor para aceptar la marca y una propiedad privada$doors(entero). Llama al constructor padre con la marca. Sobrescribe el métododescribe()para que devuelva"Car: [brand] with [doors] doors".main.php: Incluye el archivo de Car. Recibirás tres entradas: un nombre de marca, un número de puertas y una cadena con la ubicación. Crea una instancia deCar, establece su ubicación y después imprime dos líneas:- El resultado de llamar a
describe() - El resultado de llamar a
getLocation()
- El resultado de llamar a
Observa cómo funcionan juntas la herencia y los traits: Car es un Vehicle (la herencia establece la identidad), mientras que Vehicle tiene capacidad de seguimiento (el trait añade comportamiento). Podrías usar instanceof Vehicle para comprobar si algo es un vehículo, pero no existe ningún tipo «Trackable» contra el que comprobarlo: esa es la diferencia clave entre estos dos enfoques.
Pruébalo tú mismo
<?php
// Archivo principal - crea y prueba la instancia de Car
// TODO: Incluye el archivo Car.php
// Leer entradas
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: Crea una instancia de Car con brand y doors
// TODO: Establece la ubicación del coche
// TODO: Imprime el resultado de describe()
// TODO: Imprime el resultado de getLocation()
?>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 la POO
Archivos externosIntroducción a la POOClases frente a objetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Repaso: calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasRepaso - Jerarquía de empleados7Encapsulación
Público, protegido, privadoModificadores de acceso en profundidadGetters y settersOcultación de la informaciónPromoción del constructor (8.0)Repaso: sistema de registros de estudiantes10Conceptos avanzados de OOP
Composición vs. herenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibras (PHP 8.1)Análisis profundo de la clonación de objetosGeneradores e iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Namespaces y carga automática
Introducción a los NamespacesLa palabra clave useEstándar de carga automática PSR-4Autoloader de ComposerRepaso: proyecto organizado5Interfaces y contratos
Introducción a las interfacesImplementación de interfacesImplementación de múltiples interfacesInterfaces vs. clase abstractaTipado con interfacesRepaso - 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 __unserializeRepaso: 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)Repaso: gestor de cuentas bancarias6Polimorfismo
Repaso de la sobrescritura de métodosPolimorfismo mediante interfacesAnotaciones de tipo y tipos uniónEnlace estático tardíoRepaso: procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos entre TraitsMétodos abstractos en TraitsTraits frente a la herencia12Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de PHP online