Desarrollo backend

PHP 8.4 en producción: nuevas funcionalidades, JIT y rendimiento real mejorado

Ruslan Ismailov Publicado 14 min de lectura
P

Introducción: PHP 8.4 en el ecosistema de 2026

PHP 8.4 se lanzó en noviembre de 2024 y para 2026 se ha convertido en el estándar de facto para nuevos proyectos en producción. El ecosistema ha madurado: Laravel 11+ soporta de forma nativa todas las novedades de la versión, los paquetes de Composer han añadido compatibilidad de forma masiva, y Docker Hub ofrece imágenes oficiales php:8.4-fpm con soporte industrial. Si tu stack todavía usa PHP 8.2 o 8.3, este artículo te dará argumentos sólidos para la actualización y un plan de acción concreto.

Analizaremos no los mensajes de marketing, sino los cambios reales: qué mejoró en JIT, qué construcciones de sintaxis ahorran tiempo de desarrollo de verdad, qué breaking changes te esperan durante la migración y cómo construir un contenedor Docker óptimo para PHP 8.4.

Principales novedades de sintaxis

Property Hooks

La novedad más comentada de PHP 8.4 son los property hooks (RFC: Property Hooks). Permiten definir la lógica de get y set directamente en la declaración de la propiedad, sin necesidad de métodos accesores explícitos.

class User\n{\n    public string $fullName {\n        get => $this->firstName . ' ' . $this->lastName;\n        set(string $value) {\n            [$this->firstName, $this->lastName] = explode(' ', $value, 2);\n        }\n    }\n\n    public function __construct(\n        public string $firstName,\n        public string $lastName,\n    ) {}\n}\n\n$user = new User('Ivan', 'Petrov');\necho $user->fullName;         // Ivan Petrov\n$user->fullName = 'Anna Sidorova';\necho $user->firstName;        // Anna\n

Los hooks también funcionan en interfaces: puedes declarar que una propiedad debe ser readable o writable sin dictar la implementación. Esto transforma los patrones arquitectónicos: los ValueObject y DTO se vuelven más compactos, y los transformadores DTO en Laravel Resource obtienen validación nativa a nivel de asignación.

Asymmetric Visibility

La visibilidad asimétrica permite definir distintos modificadores de acceso para la lectura y la escritura de una misma propiedad:

class Order\n{\n    public private(set) int $itemCount = 0;\n\n    public function addItem(): void\n    {\n        $this->itemCount++; // OK — dentro de la clase\n    }\n}\n\n$order = new Order();\n$order->addItem();\necho $order->itemCount; // OK — lectura pública\n$order->itemCount = 5; // Fatal error — escritura bloqueada desde fuera\n

Utilidad práctica: inmutabilidad sin readonly en casos donde el valor debe poder cambiar dentro de la clase pero estar protegido desde el exterior. Funciona muy bien con objetos de dominio y Aggregate Root en arquitecturas DDD.

Nueva sintaxis sin paréntesis innecesarios (new sin paréntesis en cadenas)

PHP 8.4 elimina una molestia clásica: ahora puedes llamar métodos sobre una expresión new sin envolverla en paréntesis:

// PHP 8.3 y anteriores\n$result = (new QueryBuilder())->select('*')->from('users')->get();\n\n// PHP 8.4\n$result = new QueryBuilder()->select('*')->from('users')->get();\n

Es un detalle menor, pero en bases de código con uso intensivo de Fluent Interface, la legibilidad mejora notablemente.

Lazy Objects

Soporte nativo para la inicialización perezosa de objetos mediante ReflectionClass::newLazyGhost() y newLazyProxy(). Symfony y Laravel ya utilizan este mecanismo en sus contenedores DI:

$reflector = new ReflectionClass(HeavyService::class);\n$lazy = $reflector->newLazyGhost(function (HeavyService $instance) {\n    $instance->__construct(/* deps */);\n});\n// El constructor no se invoca hasta el primer acceso a una propiedad\n

Nuevas funciones array_*

PHP 8.4 añade array_find(), array_find_key(), array_any() y array_all() — primitivas funcionales que antes se simulaban con array_filter + reset:

$users = [['name' => 'Alice', 'age' => 30], ['name' => 'Bob', 'age' => 17]];\n\n$adult = array_find($users, fn($u) => $u['age'] >= 18);\n// ['name' => 'Alice', 'age' => 30]\n\n$allAdults = array_all($users, fn($u) => $u['age'] >= 18);\n// false\n

JIT en PHP 8.4: qué cambió y cómo configurarlo

Evolución del JIT desde la versión 8.0

El JIT (compilador Just-In-Time) apareció en PHP 8.0 como función experimental. En las versiones 8.1–8.3 fue madurando, pero para las aplicaciones web típicas la mejora era modesta: el JIT es eficaz en código computacionalmente intensivo (matemáticas, algoritmos), no en tareas I/O-bound.

PHP 8.4 rediseñó la estrategia JIT:

  • Tracing JIT activado por defecto en el nuevo modo tracing, en sustitución del obsoleto modo function.

  • Compilación mejorada de closures y funciones flecha.

  • Reducción de la sobrecarga del JIT cuando no se detectan rutas calientes (arranque en frío más rápido).

  • Soporte JIT añadido para operaciones con cadenas en determinados escenarios.

Configuración del JIT en php.ini

; Activar opcache (requisito previo para JIT)\nopcache.enable=1\nopcache.enable_cli=1\nopcache.memory_consumption=256\nopcache.jit_buffer_size=128M\n\n; Modo JIT: tracing — recomendado para PHP 8.4\n; Formato: CRTO (cuatro dígitos)\n; opcache.jit=1255 — tracing JIT, optimización agresiva\nopcache.jit=1255\n

Desglose de opcache.jit=1255: C=1 (no desactivar JIT al superar el buffer), R=2 (perfilado en bucles calientes), T=5 (tracing), O=5 (optimización máxima). Para servidores API en Laravel, recomendamos comenzar con 1205 y medir los resultados bajo carga real.

Cuándo el JIT ofrece mejoras reales

El JIT muestra su máximo efecto en tareas como:

  • Generación de informes con cálculos numéricos pesados

  • Procesamiento de imágenes (GD, Imagick)

  • Parsing de documentos XML/JSON grandes en bucle

  • Algoritmos de ordenación y búsqueda en PHP sin extensiones externas

Para aplicaciones CRUD con MySQL/PostgreSQL y Redis, la mejora del JIT suele ser del 3–8%. La ganancia real en estos casos proviene de la optimización del precalentamiento de OPcache y el preloading, no del JIT.

Benchmarks reales: PHP 8.3 vs PHP 8.4

Presentamos los resultados de pruebas independientes en hardware idéntico (2 vCPU, 4 GB RAM, Ubuntu 24.04):

Prueba 1: Fibonacci (recursión, código computacional)

function fib(int $n): int {\n    return $n <= 1 ? $n : fib($n - 1) + fib($n - 2);\n}\n// fib(35), 100 iteraciones\n
  • PHP 8.3 (sin JIT): 4,82 s

  • PHP 8.3 (JIT 1255): 1,91 s

  • PHP 8.4 (sin JIT): 4,61 s

  • PHP 8.4 (JIT 1255): 1,43 s — mejora del 25% respecto a 8.3+JIT

Prueba 2: Petición HTTP en Laravel (CRUD real)

Entorno: Laravel 11, PostgreSQL, caché Redis, 1000 peticiones (ab -n 1000 -c 50):

  • PHP 8.3: 312 req/s, latencia p95 198 ms

  • PHP 8.4: 341 req/s, latencia p95 179 ms — mejora ~9% en throughput

Prueba 3: array_find vs implementación manual

// Método antiguo\n$found = reset(array_filter($items, fn($i) => $i['active']));\n\n// PHP 8.4\n$found = array_find($items, fn($i) => $i['active']);\n

Con un array de 100.000 elementos, array_find nativa es un 18–22% más rápida que el equivalente personalizado, gracias al early exit a nivel de código C.

Prueba 4: Property Hooks vs __get/__set

Medición con 500.000 operaciones de lectura/escritura: los property hooks son un 12% más rápidos que los métodos mágicos __get/__set, ya que no requieren invocación mediante dynamic dispatch.

Deprecaciones y Breaking Changes

Antes de actualizar, debes tener en cuenta los siguientes cambios:

Funciones y características eliminadas

  • mysqli_ping() y mysqli::ping() — eliminadas. Usa reconnect a nivel del pool de conexiones.

  • La constante E_STRICT ha sido eliminada (estaba deprecated desde 8.0).

  • La conversión implícita de null a cadena en parámetros de funciones ahora genera TypeError en algunos casos.

  • Las funciones lcg_value() y srand() sin argumento están deprecated.

Cambios de comportamiento

  • Las funciones de entidades HTML (htmlspecialchars, htmlentities) ahora usan ENT_QUOTES | ENT_SUBSTITUTE por defecto en lugar de ENT_COMPAT. Revisa la protección XSS en plantillas legacy.

  • round() ahora cumple más estrictamente con IEEE 754 en casos extremos — pueden aparecer discrepancias en cálculos financieros.

  • La clase GMP ha sido renombrada a \\GMP, y varias funciones han recibido tipos de retorno explícitos.

Sintaxis obsoleta (deprecated)

  • Llamada a get_class() sin argumento dentro de métodos estáticos.

  • Parámetros nullable implícitos: function foo(Bar $b = null) — debe escribirse explícitamente como ?Bar $b = null.

Migración de un proyecto existente: checklist paso a paso

  1. Auditoría de dependencias. Ejecuta composer why-not php:8.4 para identificar paquetes sin compatibilidad. En proyectos Laravel, asegúrate de usar Laravel 10.48+ o 11.x.

  2. Análisis estático. Ejecuta phpstan analyse --level=8 y rector process --dry-run con el conjunto de reglas de PHP 8.4. Rector corregirá automáticamente los argumentos nullable, las llamadas obsoletas a get_class() y otros patrones.

  3. Prueba de deprecated warnings. Activa temporalmente E_DEPRECATED | E_USER_DEPRECATED en error_reporting y ejecuta la suite completa de tests. Registra en archivo, no en stderr.

  4. Actualización de la imagen Docker. Cambia FROM php:8.3-fpm por FROM php:8.4-fpm, reconstruye y ejecuta smoke tests.

  5. Verificación de extensiones. Asegúrate de que las extensiones PECL utilizadas (Redis, Imagick, swoole, xdebug) tengan builds para PHP 8.4.

  6. Pruebas de carga. Compara la latencia p50/p95/p99 y la utilización de CPU antes y después de la actualización usando k6 o Gatling.

  7. Despliegue gradual. Usa un feature flag o canary deployment: primero dirige el 5% del tráfico a los nodos PHP 8.4, mide el error rate con Sentry y luego aumenta progresivamente.

Integración con Docker: imágenes PHP 8.4 y optimización del contenedor

Dockerfile base para producción

FROM php:8.4-fpm-alpine AS base\n\nRUN apk add --no-cache \\\n    libpq-dev \\\n    libzip-dev \\\n    && docker-php-ext-install \\\n        pdo_pgsql \\\n        zip \\\n        opcache\n\n# Copiamos el php.ini optimizado\nCOPY docker/php/opcache.ini /usr/local/etc/php/conf.d/opcache.ini\n\nFROM base AS deps\nCOPY composer.json composer.lock ./\nRUN composer install --no-dev --optimize-autoloader --no-scripts\n\nFROM base AS production\nCOPY --from=deps /app/vendor ./vendor\nCOPY . .\nRUN composer dump-autoload --optimize\n\nUSER www-data\nCMD [\"php-fpm\"]\n

opcache.ini para PHP 8.4 en contenedor

[opcache]\nopcache.enable=1\nopcache.memory_consumption=256\nopcache.max_accelerated_files=20000\nopcache.validate_timestamps=0\nopcache.save_comments=1\nopcache.jit=1255\nopcache.jit_buffer_size=128M\n; Preloading para Laravel\nopcache.preload=/var/www/html/bootstrap/preload.php\nopcache.preload_user=www-data\n

Importante: en el contenedor establece opcache.validate_timestamps=0 — los archivos no cambian tras la construcción de la imagen, por lo que verificar el timestamp solo consume CPU innecesariamente. Durante el desarrollo, monta un php.ini separado con validate_timestamps=1.

Build multi-stage y tamaño de la imagen

La imagen Alpine php:8.4-fpm-alpine pesa aproximadamente 80 MB frente a los 480 MB de la versión basada en Debian. Usa multi-stage build (como se muestra arriba): la imagen final de producción no contiene Composer, dependencias de desarrollo ni herramientas de build. El tamaño típico de la imagen final de una aplicación Laravel es de 120–160 MB.

Docker Compose para desarrollo local

services:\n  app:\n    build:\n      context: .\n      target: base\n    volumes:\n      - .:/var/www/html\n      - ./docker/php/dev.ini:/usr/local/etc/php/conf.d/dev.ini\n    environment:\n      PHP_IDE_CONFIG: \"serverName=Docker\"\n  nginx:\n    image: nginx:alpine\n    ports:\n      - \"8080:80\"\n  postgres:\n    image: postgres:16-alpine\n  redis:\n    image: redis:7-alpine\n

Conclusión

PHP 8.4 no es una actualización cosmética, sino un conjunto de cambios que impactan tanto en la arquitectura del código (property hooks, asymmetric visibility, lazy objects) como en el rendimiento (JIT mejorado, funciones nativas de array). Los benchmarks muestran mejoras reales: desde un 9% en aplicaciones Laravel típicas hasta un 25% en tareas computacionalmente intensivas con JIT.

Los riesgos de migración son manejables: el análisis estático con PHPStan y Rector elimina gran parte del trabajo manual, y la lista de breaking changes es más corta que en la transición de PHP 7.x a 8.x. Para la mayoría de los proyectos modernos en Laravel, la actualización de 8.3 a 8.4 cabe en un sprint con una buena cobertura de tests.

El rendimiento de PHP sigue creciendo, el ecosistema es maduro y las herramientas — desde Docker hasta Composer — están completamente preparadas. Si en 2026 tu entorno de producción aún no está en PHP 8.4, es una deuda técnica que vale la pena saldar.

Tecnologías

Etiquetas

Ruslan Ismailov

Desarrollador Senior Web / Backend. Desarrollador senior web/backend con 9 años de experiencia. Stack: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, microservicios, CI/CD. Más sobre mí →