Escribe clases idiomáticas de PHP 8: promoción de propiedades, readonly, constructores con nombre y objetos de valor inmutables.
Abrir esta lección en KodokonLlevas mucho tiempo escribiendo clases, pero PHP 8 ha dejado obsoletos varios hábitos. El más visible: la promoción de propiedades en el constructor. Añadir una palabra clave de visibilidad (private, protected, public) delante de un parámetro del constructor crea la propiedad y la asigna en un solo paso. Los tres bloques repetitivos del estilo antiguo - declaración, parámetro, asignación - se funden en uno solo.
<?php
declare(strict_types=1);
class LegacyProduct
{
private string $name;
private int $priceCents;
public function __construct(
string $name,
int $priceCents,
) {
$this->name = $name;
$this->priceCents = $priceCents;
}
}
final class Product
{
public function __construct(
private string $name,
private int $priceCents,
) {
}
public function label(): string
{
return sprintf(
'%s (%.2f EUR)',
$this->name,
$this->priceCents / 100,
);
}
}
$product = new Product('Keyboard', 4990);
echo $product->label();La visibilidad sigue siendo tu primera herramienta de encapsulación: private por defecto, protected solo si una clase hija necesita acceso, public como último recurso. Desde PHP 8.1, readonly añade una garantía más fuerte: la propiedad solo se puede escribir una vez, desde dentro del ámbito de la clase que la declara. Combinada con la promoción, produce objetos de valor inmutables en apenas unas líneas: cualquier "cambio" devuelve una nueva instancia, lo que elimina los efectos secundarios compartidos.
<?php
declare(strict_types=1);
final class Money
{
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {
}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new InvalidArgumentException(
'Currency mismatch'
);
}
return new self(
$this->amount + $other->amount,
$this->currency,
);
}
}
$total = (new Money(500, 'EUR'))
->add(new Money(250, 'EUR'));
echo $total->amount;En cuanto a los métodos, dos patrones dominan entre los desarrolladores con experiencia. Los constructores con nombre: un constructor private combinado con fábricas estáticas hace explícita cada intención y prohíbe las instanciaciones inconsistentes. Las interfaces fluidas: devolver $this (mutable) o new self(...) (inmutable) te permite encadenar llamadas. El compromiso es bien conocido: la versión inmutable es más segura pero reserva un objeto por llamada - insignificante casi siempre, medible en un bucle intensivo.
<?php
declare(strict_types=1);
final class User
{
private function __construct(
public readonly string $email,
public readonly string $role,
) {
}
public static function admin(string $email): self
{
return new self($email, 'admin');
}
public static function member(string $email): self
{
return new self($email, 'member');
}
}
$user = User::admin('lea@example.com');
echo $user->role;readonly?