Traits
Compartir implementaciones de métodos entre clases no relacionadas sin usar herencia.
2 min de lectura
Las clases de PHP solo pueden extender un padre, pero el código real a menudo necesita compartir comportamiento entre clases que, de otro modo, no pertenecerían a la misma cadena de herencia. Los traits resuelven exactamente eso.
Definiendo y usando un trait
<?php
trait Loggable {
public function log(string $message): void {
echo "[" . static::class . "] $message\n";
}
}
class Order {
use Loggable;
}
class PaymentProcessor {
use Loggable;
}
$order = new Order();
$order->log("Order created"); // [Order] Order createdUn trait se parece a una clase, pero no se puede instanciar por sí solo — use Loggable; dentro de una clase copia sus métodos, como si se hubieran escrito directamente en esa clase. Order y PaymentProcessor no comparten ninguna relación de herencia, y sin embargo ambas obtienen log().
¿Por qué no simplemente usar una clase base abstracta?
<?php
class ApiController {
use Loggable;
}
class BackgroundJob {
use Loggable;
}Si ApiController y BackgroundJob ya extienden cada una una clase padre distinta y no relacionada (algo común en aplicaciones reales), ninguna podría heredar también de una clase base compartida Loggable — PHP solo permite un extends. Un trait evita esa limitación por completo, ya que use no es herencia y puede combinarse libremente con extends.
Usar varios traits a la vez
<?php
trait Timestampable {
public ?string $createdAt = null;
public function markCreated(): void {
$this->createdAt = date("Y-m-d H:i:s");
}
}
class Article {
use Loggable, Timestampable;
}
$article = new Article();
$article->markCreated();
$article->log("Article saved");Una clase puede use varios traits en una sola sentencia, combinando el comportamiento de cada uno. Si dos traits definen un método con el mismo nombre, PHP lanza un error de conflicto fatal a menos que lo resuelvas explícitamente con un bloque insteadof/as — vale la pena saber que existe, aunque es un caso extremo que no encontrarás a menudo.
Los traits también pueden tener métodos abstractos
<?php
trait Comparable {
abstract public function getValue(): int;
public function isGreaterThan(self $other): bool {
return $this->getValue() > $other->getValue();
}
}
class Money {
use Comparable;
public function __construct(private int $cents) {}
public function getValue(): int {
return $this->cents;
}
}Un trait puede declarar un método abstract que no implementa, exigiendo que la clase que lo use lo proporcione — aquí, isGreaterThan() es lógica totalmente reutilizable que solo necesita que cada clase defina qué significa "valor" para sí misma.
Cuándo recurrir a un trait frente a una interfaz
Una interfaz dice "cualquier clase que me implemente tiene estos métodos" sin proporcionar código. Un trait realmente suministra implementaciones de métodos funcionales que se copian. Es común combinar ambos: definir una interfaz Comparable para el contrato, y un trait ComparableHelpers para la lógica compartida que se construye sobre él.
Pon a prueba lo que acabas de aprender
4 preguntas rápidas. Respóndelas todas correctamente para desbloquear la siguiente lección.
Puedes hacer el cuestionario sin una cuenta — iniciar sesión solo hace que tu resultado cuente para tu progreso.