Menu
Coddy logo textTech

Traits frente a 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 frente a la herencia. Ambos permiten la reutilización de código, pero sirven para propósitos diferentes y tienen características distintas.

La herencia establece una relación "es-un" (is-a). Una clase Dog que extiende a Animal significa que un perro es un animal. La clase hija hereda la identidad del padre y puede ser utilizada en cualquier lugar donde se espere el tipo padre.

Los traits proporcionan una capacidad "tiene-un" (has-a). Cuando una clase usa un 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 a recordar:

AspectoHerenciaTraits
Relaciónes-un (is-a)tiene-una capacidad (has-a)
LímiteSolo un padreSe permiten múltiples traits
Comprobación de tiposFunciona con instanceofSin identidad de tipo
Ideal paraRelaciones jerárquicasComportamientos compartidos entre clases no relacionadas

Usa la 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

Vamos a construir un sistema de vehículos que demuestre cuándo usar la herencia frente a los traits. Crearás una jerarquía de vehículos que comparten una identidad común a través de 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 rastreo 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: " . $this->location
    Este trait representa una capacidad de tipo "tiene un" (has-a): cualquier vehículo puede tener rastreo, pero tener rastreo no convierte a algo en un vehículo.
  • Vehicle.php — Crea una clase base Vehicle que establezca la relación "es un" (is-a). 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: " . $this->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 de Vehicle. Incluye el archivo de Vehicle. Usa la promoción de constructor para aceptar la marca y una propiedad privada $doors (integer). Llama al constructor padre con la marca. Sobrescribe el método describe() para que devuelva "Car: " . $this->brand . " with " . $this->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 de ubicación. Crea una instancia de Car, establece su ubicación y luego imprime dos líneas:
    • El resultado de llamar a describe()
    • El resultado de llamar a getLocation()

Observa cómo la herencia y los traits trabajan juntos aquí: Car es un Vehicle (la herencia establece la identidad), mientras que Vehicle tiene capacidad de rastreo (el trait añade comportamiento). Podrías usar instanceof Vehicle para verificar si algo es un vehículo, pero no hay un tipo "Trackable" contra el cual verificar; esa es la diferencia clave entre estos dos enfoques.

Hoja de referencia

Usa la herencia para relaciones "es-un" y los traits para capacidades "tiene-un".

La herencia establece identidad: una clase hija es un tipo de clase padre y puede usarse en cualquier lugar donde se espere el tipo padre.

Los traits añaden comportamiento sin cambiar la identidad de la clase: una clase tiene funcionalidad pero no se convierte en esa cosa.

<?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: Cat TIENE capacidad de registro (logging)
trait Loggable {
    public function log(string $msg): void {
        echo "Log: $msg";
    }
}

class Cat extends Animal {
    use Loggable;
}
AspectoHerenciaTraits
Relaciónes-uncapacidad tiene-un
LímiteSolo un padre únicoSe permiten múltiples traits
Comprobación de tiposFunciona con instanceofSin identidad de tipo
Ideal paraRelaciones jerárquicasComportamientos compartidos entre clases no relacionadas

Usa la herencia para relaciones jerárquicas donde las clases comparten una identidad común. Usa traits para comportamientos compartidos entre clases no relacionadas.

Pruébalo tú mismo

<?php
// Archivo principal - crear y probar la instancia de Car

// TODO: Incluir el archivo Car.php

// Leer entradas
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));

// TODO: Crear una instancia de Car con marca y puertas

// TODO: Establecer la ubicación del coche

// TODO: Imprimir el resultado de describe()

// TODO: Imprimir 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