El Grupo PHP ha publicado la versión 8.5 del lenguaje de programación de código abierto que impulsa gran parte de la Web, incluidos los sitios que utilizan el CMS WordPress.
El lanzamiento de PHP 8.5 en noviembre ha supuesto el segundo año del compromiso de la comunidad PHP de ofrecer actualizaciones importantes con periodicidad anual, seguidas de dos años completos de soporte activo para cada versión.
Aunque la versión 8.5 es totalmente nueva, ya la hemos incluido en nuestra evaluación comparativa anual de PHP, junto con una variedad de plataformas y frameworks CMS populares.
Si estás planeando migrar aplicaciones PHP a la versión 8.5, necesitarás saber qué ha cambiado en esta última versión. Eso incluye nuevas funcionalidades que podrías aprovechar para mejorar tu código y antiguas funcionalidades que los desarrolladores de PHP se disponen a eliminar.
Esto es lo que consideramos lo más destacado de la nueva versión:
Nuevas funcionalidades y mejoras en PHP 8.5
Comencemos con las novedades en el código base de PHP. Estos cambios suelen comenzar como Solicitudes de Comentarios (RFC) que, con el tiempo, pueden aprobarse y asignarse a una futura versión de PHP.
Las nuevas funcionalidades que se describen a continuación son las que acaparan la mayor parte de la atención en torno a PHP 8.5.
Llamadas a funciones en cadena con un operador pipe
Un nuevo operador de pipe (|>) encadena las llamadas a funciones de un modo que resultará vagamente familiar a los programadores de JavaScript. El pipe opera de izquierda a derecha, pasando un único valor a lo largo de la cadena en cada paso.
Con versiones anteriores de PHP, los programadores podrían haber realizado una tarea similar anidando funciones o recorriendo una serie de llamadas a funciones sobre el valor devuelto en cada paso.
Aquí hay un ejemplo sencillo que utiliza el nuevo operador pipe:
$text = ' New-in-php-8.4 ';
$result = $text
|> trim(...)
|> (fn($str) => str_replace('4', '5', $str))
|> (fn($str) => str_replace('-', ' ', $str))
|> strtoupper(...);
var_dump($result);
// string(14) "NEW IN PHP 8.5"
(Ten en cuenta que estamos utilizando la sintaxis de first-class callables (...) introducida en PHP 8.1 con las llamadas a las funciones trim() y strtoupper())
La cadena pipe superior podría escribirse en una sola línea, pero se supone que la legibilidad es uno de los beneficios de este nuevo operador.
Lo anterior equivale a anidar esas operaciones (en orden inverso) de la siguiente manera:
$text = " New-in-php-8.4 ";
$result = strtoupper(
str_replace(‘-, ' ',
str_replace('4', '5',
trim($text)
)
)
);
Alternativamente, un programador podría haber completado la tarea en versiones anteriores de PHP así:
$text = " New-in-php-8.4 ";
$result = trim($text);
$result = str_replace('4', '5', $result);
$result = str_replace(‘-, ' ', $result);
$result = strtoupper($result);
Analizar (o Parsear) URLs con la nueva extensión URI
Las URL (también conocidas como URI para los más exigentes) son esenciales para la navegación web, pero la función parse_url(), integrada en PHP desde la versión 4, es conocida por tener problemas con entradas mal formadas que pueden provocar errores al intentar manipular o validar direcciones de sitios web.
Para mejorar el análisis sintáctico de las URL, PHP 8.5 incorpora las bibliotecas uriparser y Lexbor para dar soporte a los estándares RFC 3986 y WHATWG URL, respectivamente.
Puedes invocar la biblioteca uniparser empezando a trabajar con la nueva extensión URI de la siguiente manera:
$uri = new UriRfc3986Uri("https://kinsta.com/blog/php-8-5/");
echo $uri->getScheme(); // https
echo $uri->getHost(); // kinsta.com
echo $uri->getPath(); // /blog/php-8-5
Alternativamente, puedes elegir la biblioteca Lexbor WHATWG URL así:
$uri = new UriWagWgUrl("https://kinsta.com/blog/php-8-5/");
echo $uri->getScheme(); // https
echo $uri->getUnicodeHost(); // kinsta.com
echo $uri->getAsciiHost(); // kinsta.com
echo $uri->getPath(); // /blog/php-8-5
Los ejemplos anteriores son los más básicos. Las dos bibliotecas representadas por la extensión URI en PHP 8.5 comparten algunas funcionalidades y también presentan diferencias significativas.
Una diferencia importante es que la librería (que implementa) RFC 3986 soporta tanto representaciones «raw» (sin procesar/tal cual) como «normalized-decoded» (decodificadas/normalizadas) de las URIs. Esto puede ser útil al trabajar con entradas y salidas que contienen percent-encoding (codificación de porcentaje). Por ejemplo, en un navegador, estas dos URIs son idénticas:
En versiones anteriores de PHP, se podía empezar con rawurldecode() y rawurlencode() (que también cumplen con RFC 3986), pero la nueva extensión está lista para trabajar con todos los componentes de los URI desde el primer momento, estén codificados o no.
Aquí tienes algunos ejemplos extraídos directamente de la RFC en la que se basa la nueva API de análisis sintáctico:
$uri = new UriRfc3986Uri("https://%61pple:p%61ss@ex%61mple.com/foob%61r?%61bc=%61bc");
echo $uri->getRawUserInfo(); // %61pple:p%61ss
echo $uri->getUserInfo(); // apple:pass
echo $uri->getRawUsername(); // %61pple
echo $uri->getUsername(); // apple
echo $uri->getRawPassword(); // p%61ss
echo $uri->getPassword(); // pass
echo $uri->getRawHost(); // ex%61mple.com
echo $uri->getHost(); // example.com
echo $uri->getRawPath(); // /foob%61r
echo $uri->getPath(); // /foobar
echo $uri->getRawQuery(); // %61bc=%61bc
echo $uri->getQuery(); // abc=abc
Cuando se utiliza la biblioteca URL WHATWG con la nueva extensión, todos las URI se tratan como «raw», por lo que no hay un conjunto separado de funciones para soportar un formato alternativo. Pero la biblioteca puede convertir entre los caracteres ASCII y Unicode que suelen aparecer en las URI.
Sé estricto con una nueva directiva INI max_memory_limit
Dicen que un gran poder conlleva una gran responsabilidad. Si ese poder incluye elegir cuánta memoria del servidor puede intentar utilizar tu aplicación PHP, podrías ser responsable de caídas de la aplicación cuando los procesos consuman más memoria de la disponible.
Parte de una instalación típica de PHP es un archivo php.ini con información de configuración que incluye una directiva que especifica un límite de consumo de memoria para cualquier proceso (o hilo) PHP. Una directiva INI común para un límite de memoria de 128 MB tiene este aspecto:
// php.ini
memory_limit 128M
En algunas plataformas de alojamiento, los desarrolladores de aplicaciones PHP pueden anular memory_limit sobre la marcha utilizando la función ini_set() en su código:
ini_set(‘memory_limit’, ‘256M’);
// Start code that requires up to 256 MB of memory
También puedes pasar a la función el valor -1, como ini_set('memory_limit', '-1') – para no imponer ningún límite.
Anular la directiva INI para un límite de memoria puede ser arriesgado para los desarrolladores que no estén íntimamente familiarizados con las configuraciones de memoria de los servidores en los que se ejecutarán sus aplicaciones. Si uno o varios hilos PHP intentan consumir más memoria de la permitida, la aplicación puede bloquearse sin previo aviso en tiempo de ejecución.
PHP 8.5 añade una directiva INI max_memory_limit que sirve como límite máximo, incluso en configuraciones en las que los desarrolladores tienen acceso a init_set() para ajustar el uso de memoria en su código.
Aquí tienes entradas de ejemplo en el archivo php.ini de una instalación de PHP 8.5:
// php.ini
max_memory_limit 256M
memory_limit 128M
Con un max_memory_limit de 256 MB, esto es lo que ocurre en nuestro código PHP:
ini_set('memory_limit', '256M'); // This is OK
ini_set('memory_limit', '512M'); // Fail with warning
ini_set('memory_limit', '-1'); // Fail with warning
Intentar establecer un nuevo límite de memoria de 512 MB (o ilimitado) por encima no tendrá éxito. En su lugar, PHP establecerá el límite de memoria en el valor asignado a max_memory_limit en el archivo php.ini y emitirá una advertencia. (El mensaje de advertencia podría mostrarse en pantalla y registrarse, dependiendo de la configuración del informe de errores de la instalación de PHP)
Un enfoque inteligente para los desarrolladores de PHP 8.5 sería utilizar la función ini_get() para ver si se ha definido el nuevo límite máximo, como ini_get('max_memory_limit') – y luego ajustar según el valor devuelto. Con versiones de PHP anteriores a la 8.5, esa llamada devolvería con seguridad false.
Obtener el primer o último valor de un array
Que levante la mano quien pensara que PHP ya tenía funciones para leer los valores almacenados como primer o último elemento de un array.
Resulta que no. Pero desde PHP 7.3, cuenta con funciones para descubrir la primera y la última clave de un array. Por lo tanto, para encontrar el primer y el último valor, puedes emplear las funciones array_key_first() o array_key_last()y, a continuación, utilizar las claves devueltas para hacer referencia a los valores que estás buscando:
$array = ["One", "Two", "Three"];
echo $array[array_key_first($array)]; // "One"
PHP 8.5 elimina un paso para esa tarea y te permite alcanzar los valores directamente con las nuevas funciones array_first() y array_last().
Todo es muy sencillo:
$array = ["One", "Two", "Three"];
echo array_first($array); // "One"
echo array_last($array); // "Three"
echo array_last([]); // null
Arriba, puedes ver que un array vacía devolverá null, pero eso por sí solo no confirma que todo el array esté vacío, ya que un valor de array puede ser nulo:
echo array_last([1, 2, null]); // null
Obtener recordatorios para utilizar el valor de retorno de una función
PHP 8.5 añade un nuevo atributo #[NoDiscard] que indica que el valor de retorno de una función puede ser crítico. PHP confirmará que el valor de retorno se consume de algún modo y, si no es así, lanzará una advertencia.
Un ejemplo sencillo:
#[NoDiscard("this message property will be appended to the built-in warning.")]
function foo(): string {
return 'bar';
}
// Warning:
// The return value of function foo() is expected to be consumed,
// this message property will be appended to the built-in warning.
foo();
// This will not trigger a warning:
$result = foo();
// Also satisfactory is the (void) cast:
(void) foo();
En el ejemplo anterior, el valor de retorno de la función definida no se utiliza en absoluto en primera instancia, lo que desencadena una advertencia. Pero al asignarlo a la variable $result o lanzarlo como void, se consideró que el valor se había consumido.
Los autores de la RFC detrás de esta novedad en PHP 8.5 describieron usos más convincentes para este atributo que el simple ejemplo anterior. Uno de los escenarios era una función crítica con un informe de errores más complejo que un simple éxito/fracaso (pass/fail), y que se transmitía mejor a través del valor de retorno de la función.
Otras mejoras relacionadas con los atributos
Además del nuevo atributo #[NoDiscard], la nueva versión incluye otras mejoras en la funcionalidad de los metadatos de atributos:
- Ahora los atributos pueden apuntar a constantes.
- El atributo
#[Override]puede aplicarse ahora a propiedades. - El atributo
#[Deprecated]puede utilizarse en rasgos y constantes. - Se puede utilizar un nuevo atributo
#[\DelayedTargetValidation]para suprimir los errores en tiempo de compilación de los atributos principales y de extensión que se utilizan en objetivos no válidos.
Depreciaciones y eliminaciones en PHP 8.5
Con cada lanzamiento de PHP se incluye una lista de funcionalidades que se eliminarán en futuras versiones. El uso de características obsoletas en tu código generará advertencias. Cuando finalmente se eliminen de PHP, su uso puede provocar errores fatales.
Estos son algunos elementos destacados que han quedado obsoletos o se han eliminado en PHP 8.5:
- El operador backtick como alias de
shell_exec()ha quedado obsoleto. - Los nombres de reparto no canónicos
(boolean),(integer),(double), y(binary)han quedado obsoletos. En su lugar, utiliza(bool),(int),(float), y(string). - Se ha eliminado el ajuste INI disable_classes, ya que provoca que se rompan varias suposiciones del motor.
- La terminación de las sentencias
casecon punto y coma en lugar de dos puntos ha quedado obsoleta. - El uso de null como desplazamiento de array o al llamar a
array_key_exists()ahora está en desuso. Utiliza una cadena vacía en su lugar. - Ya no es posible utilizar «array» y «callable» como nombres de alias de clases en
class_alias(). - Los métodos mágicos
__sleep()y__wakeup()han quedado suavemente obsoletos. En su lugar, deben utilizarse los métodos mágicos__serialize()y__unserialize(). - Ahora se emite una advertencia al convertir NAN en otros tipos.
- La desestructuración de valores que no sean arrays (distintos de null) mediante
[]olist()emite ahora una advertencia. - Ahora se emite una advertencia al convertir valores flotantes (o cadenas que parecen flotantes) a
intsi no pueden representarse como tales.
Resumen
Esto ha sido un resumen de las novedades más destacadas de la versión PHP 8.5. Estamos seguros de que el nuevo operador pipe y el análisis URI mejorado tendrán una gran acogida entre los desarrolladores. Puede que también lo tengan las nuevas funciones array_first() y array_last(), que hubiéramos apostado a que ya existían.
Pero cualquier nueva versión de PHP engloba cientos de cambios. Puedes encontrar una lista completa de las actualizaciones de PHP 8.5 en el repositorio oficial de GitHub del Grupo PHP.
Mientras tanto, aquí en Kinsta, estamos trabajando para que PHP 8.5 esté disponible para nuestros clientes de alojamiento para WordPress. Cuando esté online, podrás cambiar a la nueva versión utilizando nuestras herramientas de configuración de PHP.