Menu
Coddy logo textTech

Métodos abstractos en Traits

Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 54 de 91.

Los traits pueden proporcionar métodos listos para usar, pero a veces se necesita que la clase que utiliza el trait implemente una funcionalidad específica. Aquí es donde los métodos abstractos en los traits resultan útiles: definen un contrato que la clase que los utiliza debe cumplir.

Cuando un trait declara un método abstracto, cualquier clase que use ese trait debe implementarlo:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

$user = new User("john@example.com");
$user->sendNotification("Welcome!");

Resultado:

Sending to john@example.com: Welcome!

El trait proporciona el método sendNotification() pero depende de que getEmail() sea implementado por la clase. Esto crea un patrón potente donde el trait maneja la lógica común mientras delega los detalles específicos de la clase a la clase que lo implementa.

Si una clase utiliza el trait sin implementar el método abstracto, PHP lanza un error fatal. Esto garantiza que los traits puedan depender de forma segura de la existencia de ciertos métodos, haciendo que su código sea más predecible y mantenible.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de precios donde diferentes tipos de productos calculan sus precios finales de manera distinta, pero todos comparten una lógica de descuento común a través de un trait con un método abstracto.

Organizarás tu código en tres archivos:

  • Discountable.php — Crea un trait llamado Discountable que proporcione la funcionalidad de descuento. El trait debe tener:
    • Un método abstracto getBasePrice(): float que las clases que usen este trait deben implementar
    • Un método applyDiscount(int $percent) que calcula y devuelve el precio después de aplicar el porcentaje de descuento al precio base
    • Un método getFinalPrice(int $percent) que devuelve una cadena formateada: "Final price: $[discounted_price]" con 2 decimales
    El trait maneja todos los cálculos de descuento, pero depende de que cada clase le indique cuál es el precio base.
  • Product.php — Crea una clase Product que use el trait Discountable. Incluye el archivo del trait. Usa la promoción de constructor para definir un $name (string) privado y un $price (float) privado. Implementa el método requerido getBasePrice() para devolver el precio del producto.
  • main.php — Incluye el archivo Product. Recibirás tres entradas: un nombre de producto, un precio y un porcentaje de descuento. Crea una instancia de Product e imprime dos líneas:
    • El precio base formateado como "Base: $[price]" con 2 decimales
    • El resultado de llamar a getFinalPrice() con el porcentaje de descuento

Este patrón es potente porque el trait Discountable puede ser utilizado por cualquier clase — productos, servicios, suscripciones — siempre que implementen getBasePrice(). El trait proporciona la lógica de descuento compartida mientras que cada clase define de dónde proviene su precio base.

Hoja de referencia

Los traits pueden declarar métodos abstractos que deben ser implementados por cualquier clase que use el trait:

<?php
trait Notifiable {
    abstract public function getEmail(): string;
    
    public function sendNotification(string $message): void {
        echo "Sending to " . $this->getEmail() . ": $message";
    }
}

class User {
    use Notifiable;
    
    public function __construct(private string $email) {}
    
    public function getEmail(): string {
        return $this->email;
    }
}

El trait proporciona métodos listos para usar mientras requiere que la clase implemente una funcionalidad específica. Si una clase usa el trait sin implementar el método abstracto, PHP lanza un error fatal.

Este patrón permite que los traits manejen la lógica común mientras delegan los detalles específicos de la clase a la clase que los implementa.

Pruébalo tú mismo

<?php

require_once 'Product.php';

// Leer entradas
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$discountPercent = intval(trim(fgets(STDIN)));

// TODO: Crear una instancia de Product con el nombre y el precio

// TODO: Imprimir el precio base formateado como "Base: $[price]" con 2 decimales

// TODO: Imprimir el resultado de llamar a getFinalPrice() con el porcentaje de descuento

?>
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