Menu
Coddy logo textTech

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:

AspectoHerenciaTraits
Relaciónes-untiene una capacidad
LímiteSolo un padreSe permiten múltiples traits
Comprobación de tiposFunciona con instanceofSin identidad de tipo
Más adecuado paraRelaciones jerárquicasComportamientos 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.

challenge icon

Desafío

Fácil

Construyamos 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 llamado Trackable que 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]"
    Este trait representa una capacidad de tipo «tiene»: cualquier vehículo puede tener seguimiento, pero tener seguimiento no convierte algo en un vehículo.
  • Vehicle.php: Crea una clase base Vehicle que 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étodo describe() que devuelva "Vehicle: [brand]". Esta clase debe usar el trait Trackable, ya que todos los vehículos de nuestra flota tendrán GPS.
  • Car.php: Crea una clase Car que extienda Vehicle. 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étodo describe() 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 de Car, establece su ubicación y después imprime dos líneas:
    • El resultado de llamar a describe()
    • El resultado de llamar a getLocation()

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()
?>
quiz iconPonte a prueba

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

Practica por tu cuenta: Compilador de PHP online