Uso de múltiples Traits
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 52 de 91.
Un solo trait es útil, pero el verdadero poder surge cuando combinas múltiples traits en una sola clase. PHP te permite incluir tantos traits como necesites, otorgando a tu clase capacidades de varias fuentes a la vez.
Para usar múltiples traits, simplemente lístelos separados por comas después de la palabra clave use:
<?php
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
trait Identifiable {
private string $id;
public function generateId(): void {
$this->id = uniqid('id_');
}
public function getId(): string {
return $this->id;
}
}
class Post {
use Timestampable, Identifiable;
public function __construct(public string $title) {
$this->generateId();
}
}
$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();
Resultado:
id_6789abc123 - 2024-01-15 10:30:00La clase Post ahora tiene métodos de ambos traits. Cada trait aporta su propia funcionalidad: Timestampable proporciona métodos relacionados con el tiempo, mientras que Identifiable gestiona IDs únicos. Este enfoque mantiene cada trait centrado en una única responsabilidad, haciendo que tu código sea más modular y reutilizable.
¿Qué sucede cuando dos traits tienen métodos con el mismo nombre? Esa es una situación de conflicto que exploraremos en la próxima lección.
Desafío
FácilVamos a construir un sistema de gestión de productos que combina múltiples traits para dotar a los productos de capacidades tanto de fijación de precios como de inventario. Cada trait manejará una única responsabilidad, y tu clase de producto obtendrá funcionalidad de ambos.
Organizarás tu código en tres archivos:
Priceable.php— Crea un trait llamadoPriceableque maneje la funcionalidad de precios. El trait debe tener:- Una propiedad privada
$price(float) - Un método
setPrice(float $price)que almacene el precio - Un método
getPrice()que devuelva el precio - Un método
getFormattedPrice()que devuelva el precio formateado como"$[price]"con 2 decimales
- Una propiedad privada
Stockable.php— Crea un trait llamadoStockableque gestione el inventario. El trait debe tener:- Una propiedad privada
$stock(integer) - Un método
setStock(int $quantity)que almacene la cantidad de stock - Un método
getStock()que devuelva el stock actual - Un método
isInStock()que devuelvatruesi el stock es mayor que 0,falseen caso contrario
- Una propiedad privada
main.php— Incluye ambos archivos de traits y crea una claseProductque utilice los traitsPriceableyStockable. Usa la promoción de constructor para definir una propiedad pública$name. El constructor también debe aceptar un precio y una cantidad de stock, utilizando los métodos de los traits para establecerlos.Recibirás tres entradas: un nombre de producto, un precio y una cantidad de stock. Crea un producto con estos valores e imprime cuatro líneas:
- El nombre del producto
- El precio formateado (usando
getFormattedPrice()) - La cantidad de stock
"Available"si está en stock, o"Out of stock"si no lo está
Esto demuestra cómo funcionan juntos múltiples traits: tu clase Product obtiene capacidades de fijación de precios de un trait y gestión de inventario de otro, manteniendo cada responsabilidad claramente separada mientras las combina en un producto con todas las funciones.
Hoja de referencia
Para usar múltiples traits en una clase, lístelos separados por comas después de la palabra clave use:
<?php
trait Timestampable {
public function getTimestamp(): string {
return date('Y-m-d H:i:s');
}
}
trait Identifiable {
private string $id;
public function generateId(): void {
$this->id = uniqid('id_');
}
public function getId(): string {
return $this->id;
}
}
class Post {
use Timestampable, Identifiable;
public function __construct(public string $title) {
$this->generateId();
}
}
$post = new Post("Hello World");
echo $post->getId() . " - " . $post->getTimestamp();
// Output: id_6789abc123 - 2024-01-15 10:30:00
Cada trait aporta su propia funcionalidad a la clase. Este enfoque mantiene cada trait enfocado en una sola responsabilidad, haciendo que el código sea más modular y reutilizable.
Pruébalo tú mismo
<?php
require_once 'Priceable.php';
require_once 'Stockable.php';
// TODO: Crear una clase Product que use los traits Priceable y Stockable
// Usar la promoción de constructor para la propiedad pública $name
// El constructor debe aceptar name, price y stock, y usar los métodos de los traits para establecer el precio y el stock
class Product {
// TODO: Usar los traits aquí
// TODO: Implementar el constructor con promoción de constructor para $name
// y establecer el precio y el stock usando los métodos de los traits
}
// Leer la entrada
$name = trim(fgets(STDIN));
$price = floatval(trim(fgets(STDIN)));
$stock = intval(trim(fgets(STDIN)));
// TODO: Crear una instancia de Product con los valores de entrada
// TODO: Imprimir el nombre del producto
// TODO: Imprimir el precio formateado usando getFormattedPrice()
// TODO: Imprimir la cantidad de stock
// TODO: Imprimir "Available" si hay stock, o "Out of stock" si no hay
?>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