PHP 8.4 se publicó el 21 de noviembre de 2024 y es la versión más interesante del ciclo 8.x desde que llegaron las enumeraciones en 8.1. No porque traiga una revolución, sino porque resuelve problemas concretos que cualquiera que lleve tiempo con PHP conoce de sobra: el boilerplate de los getters y setters, la necesidad de encadenamiento de métodos al instanciar objetos, o la falta de funciones de array que en JavaScript llevan años siendo estándar.
Si todavía estás en PHP 8.2 o 8.3, este artículo te da las razones para plantearte la actualización. Si ya usas 8.4, aquí tienes todo ordenado para que no se te escape nada.
El ciclo de versiones de PHP 8.x: dónde venimos
Desde PHP 8.0, el equipo de desarrollo mantiene un ritmo de una versión mayor al año. Cada entrega acumula mejoras sin romper la compatibilidad salvo en casos muy concretos. El resumen del ciclo:
- PHP 8.0 (2020): JIT, named arguments, expresión
match, union types, nullsafe operator (?->). - PHP 8.1 (2021): enums, fibers, readonly properties, intersection types.
- PHP 8.2 (2022): readonly classes, DNF types,
null,falseytruecomo tipos standalone. - PHP 8.3 (2023): typed class constants,
json_validate(), atributo#[Override]. - PHP 8.4 (2024): property hooks, asymmetric visibility, nuevas funciones de array, parser HTML5 en DOM, BCMath con API orientada a objetos.
PHP 8.4 tiene soporte activo hasta noviembre de 2026 y soporte de seguridad hasta noviembre de 2028, así que hay margen para adoptarlo con calma.
Property hooks: el cambio más significativo
Esto es lo que más va a afectar al código que escribes día a día. Los property hooks permiten definir lógica de lectura y escritura directamente en la declaración de una propiedad, sin métodos get*() y set*() separados.
Antes de PHP 8.4, si querías una propiedad calculada o con validación al asignar, tenías que escribir algo así:
class Usuario {
private string $firstName;
private string $lastName;
public function getFullName(): string {
return $this->firstName . ' ' . $this->lastName;
}
public function setFullName(string $value): void {
[$this->firstName, $this->lastName] = explode(' ', $value, 2);
}
}
Con PHP 8.4 puedes hacer esto:
class Usuario {
private string $firstName;
private string $lastName;
public string $fullName {
get {
return $this->firstName . ' ' . $this->lastName;
}
set(string $value) {
[$this->firstName, $this->lastName] = explode(' ', $value, 2);
}
}
}
El hook get se ejecuta cada vez que lees $usuario->fullName. El hook set se ejecuta cuando asignas $usuario->fullName = 'Ana García'. Puedes definir solo uno de los dos: si solo defines get, la propiedad es de solo lectura desde fuera.
Para propiedades simples con solo lectura calculada, hay una sintaxis abreviada:
public string $fullName {
get => $this->firstName . ' ' . $this->lastName;
}
Los property hooks funcionan también con interfaces y clases abstractas, lo que abre posibilidades interesantes para definir contratos sobre propiedades computadas sin forzar una implementación concreta.
Asymmetric visibility: leer desde cualquier sitio, escribir solo desde dentro
Otro añadido muy útil para quienes trabajan con Value Objects o entidades de dominio. La visibilidad asimétrica permite que una propiedad sea pública para lectura pero privada (o protegida) para escritura:
class Pedido {
public private(set) string $id;
public protected(set) string $estado;
public function __construct(string $id) {
$this->id = $id;
$this->estado = 'pendiente';
}
}
$pedido = new Pedido('abc-123');
echo $pedido->id; // OK: lectura pública
$pedido->id = 'otro'; // Error: escritura privada
Antes de PHP 8.4 esto requería hacer la propiedad readonly (que solo se puede asignar una vez) o crear un getter público y trabajar con una propiedad privada internamente. Con public private(set) el acceso de lectura queda limpio y sin métodos auxiliares, mientras la escritura queda protegida.
La sintaxis acepta también public protected(set) para permitir escritura desde la propia clase y sus subclases.
Las nuevas funciones de array que faltaban desde siempre
PHP 8.4 añade cuatro funciones que cualquier desarrollador de JavaScript reconocerá al instante:
array_find() y array_find_key()
$usuarios = [
['nombre' => 'Ana', 'activo' => true],
['nombre' => 'Luis', 'activo' => false],
['nombre' => 'Marta', 'activo' => true],
];
$primerActivo = array_find($usuarios, fn($u) => $u['activo']);
// ['nombre' => 'Ana', 'activo' => true]
$claveActivo = array_find_key($usuarios, fn($u) => $u['activo']);
// 0
array_find() devuelve el primer elemento que satisface la función de callback, o null si ninguno lo hace. array_find_key() devuelve la clave correspondiente.
Antes había que recurrir a array_filter() combinado con reset() o array_key_first(), que no es especialmente legible:
// Antes de PHP 8.4
$primerActivo = reset(array_filter($usuarios, fn($u) => $u['activo'])) ?: null;
array_any() y array_all()
$numeros = [1, 3, 5, 8, 11];
$hayPares = array_any($numeros, fn($n) => $n % 2 === 0);
// true (el 8 es par)
$todosPares = array_all($numeros, fn($n) => $n % 2 === 0);
// false
array_any() devuelve true si al menos un elemento cumple la condición. array_all() devuelve true si todos la cumplen. Son el equivalente de some() y every() en JavaScript.
new sin paréntesis para encadenamiento de métodos
Un detalle pequeño pero que elimina un punto de fricción real. Hasta PHP 8.3, encadenar métodos sobre una instancia nueva requería envolver el constructor entre paréntesis:
// Antes
$resultado = (new Mailer)->to($email)->subject($asunto)->send();
// PHP 8.4
$resultado = new Mailer->to($email)->subject($asunto)->send();
También funciona para acceder directamente a una propiedad: new Clase->propiedad. No es un cambio que reescriba código existente, pero en fluent interfaces y builders el resultado es más limpio.
HTML5 en la extensión DOM
La extensión DOM clásica de PHP usa libxml para parsear HTML. El problema es que libxml no soporta HTML5 de forma correcta: elementos como <template>, web components o algunas estructuras modernas se parsean mal o generan warnings molestos.
PHP 8.4 integra Lexbor, un parser HTML5 completo. Las nuevas clases están en el namespace Dom (con la D en minúsculas) para distinguirlas de las clásicas:
// Parser HTML5 nuevo (PHP 8.4)
$doc = DomHTMLDocument::createFromHTMLFile('pagina.html');
$doc = DomHTMLDocument::createFromHTML($htmlString);
// El clásico sigue funcionando
$doc = new DOMDocument();
$doc->loadHTML($htmlString);
Para scraping o procesamiento de HTML moderno, el parser nuevo maneja correctamente la especificación HTML5 y no genera los warnings que producía libxml con estructuras que no eran XHTML estricto.
BCMath con API orientada a objetos
BCMath es la librería de precisión arbitraria de PHP, útil para cálculos financieros o científicos donde los tipos float nativos no son suficientes. Hasta PHP 8.3 solo existía como funciones sueltas:
// BCMath clásico
$resultado = bcadd('1.5', '2.5', 2); // '4.00'
$resultado = bcmul($resultado, '3', 2); // '12.00'
PHP 8.4 añade la clase BcMathNumber con métodos encadenables y sobrecarga de operadores:
$a = new BcMathNumber('1.5');
$b = new BcMathNumber('2.5');
$resultado = $a->add($b)->mul('3');
echo $resultado; // 12.0
// Los operadores también funcionan
$suma = $a + $b; // BcMathNumber('4.0')
La API orientada a objetos hace el código mucho más legible cuando hay varias operaciones encadenadas.
Deprecaciones que conviene conocer antes de actualizar
PHP 8.4 marca como deprecados varios patrones que antes eran válidos. El más habitual es el nullable implícito:
// Antes: válido y muy común
function procesarTexto(string $texto = null): void { ... }
// PHP 8.4: genera deprecation warning
// Hay que escribir:
function procesarTexto(?string $texto = null): void { ... }
Si tienes una base de código grande, herramientas como Rector o php-cs-fixer pueden automatizar esta corrección con una sola regla. No es un cambio que rompa nada todavía, pero en PHP 9 se eliminará la compatibilidad.
Además, E_STRICT desaparece en PHP 8.4. Si tu código comprobaba este nivel de error específicamente, tendrás que ajustar la configuración.
Por dónde empezar con PHP 8.4
Si tienes un proyecto en PHP 8.2 o 8.3, la migración a 8.4 es bastante directa. Los pasos habituales:
- Ejecuta tu suite de tests con PHP 8.4 (en local o en CI) para detectar deprecations.
- Corrige los nullable implícitos con Rector o manualmente.
- Si usas la extensión DOM para parsear HTML, valora si el parser nuevo te conviene.
- Los property hooks y la asymmetric visibility no requieren cambiar código existente: los adoptas en código nuevo cuando te apetezca.
Para proyectos Laravel, vale la pena leer sobre cómo aprovechar PHP 8.4 junto a las mejoras de rendimiento del framework: PHP 8.4 y el rendimiento en Laravel: sacar partido al JIT. Y si te interesa cómo los property hooks encajan con el diseño orientado a objetos, hay más contexto en property hooks y el diseño orientado a objetos en PHP.
Imagen: Pexels / César Gaviria
