Lanzado el 25 de noviembre de 2021, PHP 8.1 está finalmente aquí, con varias características interesantes.

En este artículo, cubriremos en detalle las novedades de PHP 8.1. Desde sus nuevas características y mejoras de rendimiento hasta los cambios significativos y las desaprobaciones, los revisaremos todos en profundidad.

¡Siéntate bien!

Nuevas características de PHP 8.1

Empecemos por cubrir todas las nuevas características de PHP 8.1. Es una lista bastante grande.

Tipos de intersección puros

PHP 8.1 añade soporte para tipos de intersección. Es similar a los tipos de unión introducidos en PHP 8.0, pero su uso previsto es exactamente el opuesto.

Para entender mejor su uso, vamos a refrescar nuestra memoria para saber cómo funcionan las declaraciones de tipo en PHP.

Esencialmente, puedes añadir declaraciones de tipo a los argumentos de las funciones, a los valores de retorno y a las propiedades de las clases. Esta asignación se llama «type hinting» y asegura que el valor es del tipo correcto en el momento de la llamada. De lo contrario, lanza un TypeError de inmediato. A su vez, esto te ayuda a depurar mejor el código.

Sin embargo, declarar un solo tipo tiene sus limitaciones. Los tipos de unión te ayudan a superar eso al permitirte declarar un valor con múltiples tipos, y la entrada tiene que satisfacer al menos uno de los tipos declarados.

Por otro lado, el RFC describe los tipos de intersección como:

Un «tipo de intersección» requiere que un valor satisfaga varias restricciones de tipo en lugar de una sola.

…los tipos de intersección puros se especifican utilizando la sintaxis T1&T2&… y pueden utilizarse en todas las posiciones en las que se aceptan actualmente los tipos…

Obsérvese el uso del operador & (AND) para declarar tipos de intersección. En cambio, utilizamos el operador | (OR) para declarar tipos de unión.

El uso de la mayoría de los tipos estándar en un tipo de intersección dará lugar a un tipo que nunca puede cumplirse (por ejemplo, entero y cadena). Por lo tanto, los tipos de intersección solo pueden incluir tipos de clase (es decir, interfaces y nombres de clase).

Aquí hay un código de ejemplo de cómo se pueden utilizar los tipos de intersección:

class A {
    private Traversable&Countable $countableIterator;
 
    public function setIterator(Traversable&Countable $countableIterator): void {
        $this->countableIterator = $countableIterator;
    }
 
    public function getIterator(): Traversable&Countable {
        return $this->countableIterator;
    }
}

En el código anterior, hemos definido una variable countableIterator como una intersección de dos tipos: Traversable y Countable. En este caso, los dos tipos declarados son interfaces.

Los tipos de intersección también se ajustan a las reglas de varianza estándar de PHP ya utilizadas para la comprobación de tipos y la herencia. Pero hay dos reglas adicionales sobre cómo los tipos de intersección interactúan con la subtipificación. Puedes leer más sobre las reglas de variación de los tipos de intersección en su RFC.

En algunos lenguajes de programación, se pueden combinar Tipos Unión y Tipos Intersección en la misma declaración. Pero PHP 8.1 lo prohíbe. Por lo tanto, su implementación se llama tipos de intersección «pure». Sin embargo, el RFC menciona que «se deja como una característica futura».

Enums

PHP 8.1 finalmente añade soporte para enums (también llamados enumeraciones o tipos enumerados). Son un tipo de datos definido por el usuario que consiste en un conjunto de valores posibles.

El ejemplo de enums más común en los lenguajes de programación es el tipo booleano, con true y false como dos valores posibles. Es tan común que está incorporado en muchos lenguajes de programación modernos.

Según el RFC, los enums en PHP estarán restringidos a «enumeraciones unitarias» al principio:

El alcance de esta RFC se limita a las «enumeraciones unitarias», es decir, a las enumeraciones que son en sí mismas un valor, en lugar de una simple sintaxis de fantasía para una constante primitiva, y que no incluyen información adicional asociada. Esta capacidad ofrece un soporte muy ampliado para el modelado de datos, las definiciones de tipos personalizados y el comportamiento de tipo mónada. Los Enums permiten la técnica de modelado de «hacer irrepresentables los estados no válidos», lo que conduce a un código más robusto con menos necesidad de pruebas exhaustivas.

Para llegar a este punto, el equipo de PHP estudió muchos lenguajes que ya soportan las enumeraciones. Su estudio encontró que se pueden categorizar las enumeraciones en tres grupos generales: Constantes extravagantes, Objetos extravagantes, y Tipos de datos algebraicos (ADTs) completos. Es una lectura interesante.

PHP implementa los enums «Fancy Objects», con planes de extenderlo a ADTs completos en el futuro. Está modelado conceptual y semánticamente después de los tipos enumerados en Swift, Rust y Kotlin, aunque no está modelado directamente en ninguno de ellos.

El RFC utiliza la famosa analogía de los palos de una baraja para explicar cómo funcionará:

enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}

En este caso, el enunciado Suit define cuatro valores posibles: Hearts, Diamonds, Clubs y Spades. Puedes acceder a estos valores directamente utilizando la sintaxis: Suit::Hearts, Suit::Diamonds, Suit::Clubs, y Suit::Spades.

Este uso puede parecer familiar, ya que los enums se construyen sobre clases y objetos. Se comportan de forma similar y tienen casi los mismos requisitos. Los enums comparten los mismos espacios de nombres que las clases, las interfaces y los traits.

Los enums mencionados anteriormente se denominan Pure Enums.

También puedes definir Backed Enums si quieres dar un valor equivalente a un escalar a cualquier caso. Sin embargo, los enums respaldados solo pueden tener un tipo, ya sea int o string (nunca ambos).

enum Suit: string {
  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs = 'C';
  case Spades = 'S';
}

Además, todos los casos diferentes de un enum respaldado deben tener un valor único. Y nunca puedes mezclar enums puros y respaldados.

El RFC profundiza en los métodos enum, los métodos estáticos, las constantes, las expresiones constantes y mucho más. Cubrirlos todos está más allá del alcance de este artículo. Puedes consultar la documentación para familiarizarte con todas sus pros.

El tipo de devolución never

PHP 8.1 añade una nueva pista de tipo de retorno llamada never. Es súper útil para usar en funciones que siempre throwexit.

Según su RFC, las funciones de redirección de URL que siempre exit (explícita o implícitamente) son un buen ejemplo para su uso:

function redirect(string $uri): never {
    header('Location: ' . $uri);
    exit();
}
 
function redirectToLoginPage(): never {
    redirect('/login');
}

Una función never-declarada debe cumplir tres condiciones:

  • No debería tener la declaración de return definida explícitamente.
  • No debería tener la sentencia de return definida implícitamente (por ejemplo, sentencias if-else).
  • Debe terminar su ejecución con una sentencia de exit (explícita o implícitamente).

El ejemplo de redirección de URL anterior muestra el uso tanto explícito como implícito del tipo de never retorno.

El tipo de devolución never comparte muchas similitudes con el tipo de retorno void. Ambos aseguran que la función o el método no devuelve un valor. Sin embargo, difiere en que impone reglas más estrictas. Por ejemplo, una función declarada como void puede seguir return sin un valor explícito, pero no se puede hacer lo mismo con una función declarada como never.

Como regla general, utiliza  void cuando esperas que PHP continúe ejecutándose después de la llamada a la función. Usa never cuando quieras lo contrario.

Además, never se define como un tipo «inferior». Por lo tanto, cualquier método de la clase declarado never puede «nunca» cambiar su tipo de retorno a otra cosa. Sin embargo, puedes extender un método declarado void con un método declarado never.

Fiber

Históricamente, el código PHP ha sido casi siempre código síncrono. La ejecución del código se detiene hasta que se devuelve el resultado, incluso para las operaciones de E/S. Puedes imaginar por qué este proceso puede hacer que la ejecución del código sea más lenta.

Existen múltiples soluciones de terceros para superar este obstáculo y permitir a los desarrolladores escribir código PHP de forma asíncrona, especialmente para operaciones de E/S concurrentes. Algunos ejemplos populares son amphp, ReactPHP y Guzzle.

Sin embargo, no hay una manera estándar de manejar tales instancias en PHP. Además, tratar el código síncrono y asíncrono en la misma pila de llamadas conduce a otros problemas.

Los fibers son la forma en que PHP maneja el paralelismo a través de hilos virtuales (o hilos verdes). Busca eliminar la diferencia entre el código síncrono y el asíncrono permitiendo que las funciones de PHP se interrumpan sin afectar a toda la pila de llamadas.

Esto es lo que promete el RFC:

  • Añadir soporte para Fibers a PHP.
  • Introducción de una nueva clase Fiber y la correspondiente clase de reflexión ReflectionFiber.
  • Añadir clases de excepción FiberError y FiberExit para representar errores.
  • Los fibers permiten implementaciones transparentes de E/S sin bloqueo de las interfaces existentes (PSR-7, Doctrine ORM, etc.). Esto se debe a que se elimina el objeto marcador de posición (promesa). En su lugar, las funciones pueden declarar el tipo de resultado de E/S en lugar de un objeto marcador de posición que no puede especificar un tipo de resolución porque PHP no soporta genéricos.

Puede usar Fibers para desarrollar funciones PHP interrumpibles de pila completa, que luego puede usar para implementar la multitarea cooperativa en PHP. Como Fibers pone en pausa toda la pila de ejecución, puedes estar tranquilo sabiendo que no dañará el resto de tu código.

Gráfico que ilustra el flujo de ejecución del código PHP con Fibers (Fuente: PHP.net).
Gráfico que ilustra el flujo de ejecución del código PHP con Fibers (Fuente: PHP.net).

Para ilustrar el uso de los fibers, su RFC utiliza este sencillo ejemplo:

$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('fiber');
    echo "Value used to resume fiber: ", $value, "\n";
});
 
$value = $fiber->start();
 
echo "Value from fiber suspending: ", $value, "\n";
 
$fiber->resume('test');

Estás creando una «fier» en el código anterior e inmediatamente la suspendes con la cadena fiber. La declaración de eco sirve como una señal visual para la reanudación de la fibra.

Puedes recuperar este valor de cadena desde la llamada a $fiber->start().

A continuación, se reanuda el fiber con la cadena «test», que se devuelve de la llamada a Fiber::suspend(). La ejecución completa del código da como resultado una salida que dice:

Value from fiber suspending: fiber
Value used to resume fiber: test

Ese es el ejemplo de libro de texto de PHP Fibers en el trabajo. Aquí hay otro ejemplo de Fibers para realizar siete peticiones GET asíncronas.

Con todo lo dicho, la mayoría de los desarrolladores de PHP nunca tratarán con laos fibers directamente. Y el RFC incluso sugiere lo mismo:

Los fibers son una característica avanzada que la mayoría de los usuarios no utilizarán directamente. Esta característica está dirigida principalmente a los autores de bibliotecas y marcos de trabajo para proporcionar un bucle de eventos y una API de programación asíncrona. Los fibers permiten integrar la ejecución de código asíncrono sin problemas en el código síncrono en cualquier punto, sin necesidad de modificar la pila de llamadas de la aplicación o añadir código repetitivo.

No se espera que la API del fiber se utilice directamente en el código de la aplicación. Los fibers proporcionan una API de control de flujo básica y de bajo nivel para crear abstracciones de mayor nivel que luego se utilizan en el código de la aplicación.

Teniendo en cuenta sus ventajas de rendimiento, es de esperar que las bibliotecas y los frameworks de PHP aprovechen esta nueva característica. Será interesante ver cómo implementan Fibers dentro de su ecosistema.

Nuevas propiedades de readonly

PHP 8.1 añade soporte para propiedades readonly . Solo pueden ser inicializadas una vez desde el ámbito donde se declaran. Una vez inicializadas, no se puede modificar su valor nunca. Si lo hicieras, se produciría una excepción de error.

Su RFC dice:

Una propiedad readonly solo puede ser inicializada una vez, y solo desde el ámbito donde ha sido declarada. Cualquier otra asignación o modificación de la propiedad dará lugar a una excepción de error.

Aquí tienes un ejemplo de cómo puedes utilizarlo:

class Test {
    public readonly string $kinsta;
 
    public function __construct(string $kinsta) {
        // Legal initialization.
        $this->kinsta = $kinsta;
    }
}

Una vez inicializado, no hay vuelta atrás. Tener esta característica incorporada en PHP reduce en gran medida el código repetitivo que a menudo se utiliza para activar esta funcionalidad.

La propiedad readonly ofrece una fuerte garantía de inmutabilidad, tanto dentro como fuera de la clase. No importa el código que se ejecute en el medio. Llamar a una propiedad readonly siempre devolverá el mismo valor.

Sin embargo, el uso de la propiedad readonly puede no ser ideal en casos de uso específicos. Por ejemplo, solo se puede utilizar junto a una propiedad tipificada porque las declaraciones sin tipo son implícitamente null y no pueden ser readonly.

Además, establecer una propiedad readonly no hace que los objetos sean inmutables. La propiedad readonly mantendrá el mismo objeto, pero ese objeto en sí mismo puede cambiar.

Otro problema menor de esta propiedad es que no se puede clonar. Ya existe una solución para este caso particular. Investígalo si es necesario.

Definir las constantes final de la clase

A partir de PHP 8.0, puedes anular las constantes de las clases con sus sub-clases . Esto se debe a la forma en que se implementa la herencia en PHP.

Este es un ejemplo de cómo se puede anular el valor de una constante previamente declarada:

class Moo
{
    public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}  

Ahora, si las vacas quieren ser más estrictas con el comportamiento de los gatos (al menos con las constantes), pueden hacerlo con el nuevo modificador final de PHP 8.1.

Una vez que has declarado una constante como final, significa que.

class Moo
{
    final public const M = "moo";
}
 
class Meow extends Moo
{
    public const M = "meow";
}
 
// Fatal error: Meow::M cannot override final constant Moo::M

Puedes leer más sobre esto en las constantes final de clase PHP RFC.

Nuevas funciones fsync() y fdatasync()

PHP 8.1 añade dos nuevas funciones del sistema de archivos llamadas fsync() y fdatasync(). Parecerán familiares para aquellos acostumbrados a las funciones de Linux del mismo nombre. Eso es porque están relacionadas, solo que implementadas para PHP.

De hecho, esta adición ha sido muy esperada. PHP es uno de los pocos lenguajes de programación importantes que aún no implementaron fsync() y fdatasync() – es decir, hasta PHP 8.1.

La función fsync() es similar a la función fflush() de PHP, pero difiere significativamente en un aspecto. Mientras que fflush() vacía los búferes internos de la aplicación al sistema operativo, fsync() va un paso más allá y asegura que los búferes internos sean vaciados al almacenamiento físico. Esto asegura una escritura completa y persistente para que pueda recuperar los datos incluso después de una caída de la aplicación o del sistema.

Aquí tienes un ejemplo de cómo puedes utilizarlo.

$doc = 'kinsta.txt';

$kin = fopen($doc, 'ki');
fwrite($kin, 'doc info');
fwrite($kin, "\r\n");
fwrite($kin, 'more info');

fsync($kin);
fclose($kin);

Añadir la llamada fsync() al final asegura que cualquier dato retenido en el búfer interno de PHP o del sistema operativo se escriba en el almacenamiento. Todas las demás ejecuciones de código se bloquean hasta entonces.

Su función relacionada es fdatasync(). Se utiliza para sincronizar datos pero no necesariamente metadatos. Para los datos cuyos metadatos no son esenciales, esta llamada a la función hace que el proceso de escritura sea un poco más rápido.

Sin embargo, debes tener en cuenta que PHP 8.1 aún no soporta fdatasync() completamente en Windows. Simplemente actúa como un alias de fsync(). En POSIX, fdatasync() está correctamente implementada.

Nueva función array_is_list()

Los arrays de PHP pueden contener claves tanto enteras como de cadena. Esto significa que puedes usarlos para varias cosas, incluyendo listas, tablas hash, diccionarios, colecciones, pilas, colas y mucho más. Incluso puede tener arrays dentro de arrays, creando arrays multidimensionales.

Se puede comprobar eficazmente si una entrada concreta es un array, pero no es tan fácil comprobar si le faltan desplazamientos de array, claves desordenadas, etc. En resumen, no puedes verificar rápidamente si un array es una lista.

La array_is_list() function comprueba si las claves de un array están en orden secuencial empezando por 0, y sin espacios. Si se cumplen todas las condiciones, devolverá true. Por defecto, también devuelve true para arrays vacíos.

Aquí hay algunos ejemplos de su uso con condiciones truefalse :

// true array_is_list() examples
array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list(['cats', 2, 3]); // true
array_is_list(['cats', 'dogs']); // true
array_is_list([0 => 'cats', 'dogs']); // true
array_is_list([0 => 'cats', 1 => 'dogs']); // true 

// false array_is_list() examples 
array_is_list([1 => 'cats', 'dogs']); // as first key isn't 0
array_is_list([1 => 'cats', 0 => 'dogs']); // keys are out of order
array_is_list([0 => 'cats', 'bark' => 'dogs']); // non-integer keys
array_is_list([0 => 'cats', 2 => 'dogs']); // gap in between keys 

Una lista de array de PHP con claves fuera de orden es una fuente potencial de errores. El uso de esta función para imponer una estricta adherencia a los requisitos de la lista antes de avanzar en la ejecución del código es una gran adición a PHP.

Nuevas funciones Sodium XChaCha20

Sodium es una biblioteca criptográfica moderna y fácil de usar para el cifrado, descifrado, hash de contraseñas, firmas y más. El paquete PECL libsodium añade una envoltura para Sodium para que los desarrolladores de PHP puedan utilizarla.

Incluso empresas tecnológicas líderes como Facebook, Discord, Malwarebytes y Valve utilizan libsodium para asegurar a sus usuarios con conexiones rápidas y seguras.

libsodium soporta el algoritmo de cifrado XChaCha20 para cifrar y descifrar datos, especialmente para el cifrado de flujos. Asimismo, la extensión PECL libsodium ya soporta XChaCha20, pero solo con el código de autenticación de mensajes Poly1305.

Muchas aplicaciones PHP utilizan XChaCha20 directamente para el cifrado de flujos. Para facilitar las cosas, a partir de PHP 8.1, tendrás tres nuevas funciones para cifrar o descifrar datos con XChaCha20 sin autenticación de por medio. Este modo se llama «detached mode».

Las nuevas funciones de XChaCha20 son:

  • sodium_crypto_stream_xchacha20_keygen: Devuelve una clave aleatoria segura para su uso con sodium_crypto_stream_xchacha20.
  • sodium_crypto_stream_xchacha20: Expande la clave y el nonce en un keystream de bytes pseudoaleatorios.
  • sodium_crypto_stream_xchacha20_xor: Encripta un mensaje utilizando un nonce y una clave secreta (sin autenticación).

Además, hay dos nuevas constantes PHP definidas en el espacio de nombres global:

  • SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES (asignado 32)
  • SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES (asignado 24)

Sin embargo, utilízalo con precaución. Como no hay autenticación, la operación de descifrado es vulnerable a los ataques comunes de texto cifrado.

Puedes leer más sobre su uso y requisitos en la página de GitHub.

Nueva clase IntlDatePatternGenerator

La biblioteca ICU subyacente de PHP soporta la creación de formatos de fecha y hora localizados, pero no es totalmente personalizable.

Por ejemplo, si quieres crear datos y formatos de hora específicos para cada localidad hasta PHP 8.0, puedes utilizar la constante predefinida IntlDateFormatter para hacerlo de 6 maneras:

  • IntlDateFormatter::LONG: Más largo, como el 10 de noviembre de 2017 o las 23:22:33
  • IntlDateFormatter::MEDIUM: Un poco más corto, como el 10 de noviembre de 2017
  • IntlDateFormatter::SHORT: Solo numérico, como 10/11/17 o 11:22pm

Cada uno de ellos tiene también sus propias variantes RELATIVE_, que establece el formato de la fecha dentro de un rango limitado antes o después de la fecha actual. En PHP, los valores son ayer, hoy y mañana.

Digamos que quieres usar la versión larga para el año y la versión corta para el mes, como 10/11/2017. A partir de PHP 8.0, no se puede.

En PHP 8.1+, puedes especificar qué formatos usar para la fecha, el mes y la hora con la nueva clase IntlDatePatternGenerator. Puedes dejar el orden exacto de estos componentes al formateador.

Debes tener en cuenta que aunque esta clase solo tiene la palabra Date en ella, es consistente con el DateTimePatternGenerator de ICU. Esto significa que también puedes usarlo para crear formatos de tiempo flexibles. Para simplificar la nomenclatura, el equipo de PHP ha optado por el término más corto IntlDatePatternGenerator.

He aquí un ejemplo extraído directamente de su RFC:

$skeleton = "YYYYMMdd";
 
$today = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-04-24');
 
$dtpg = new \IntlDatePatternGenerator("de_DE");
$pattern = $dtpg->getBestPattern($skeleton);
echo "de: ", \IntlDateFormatter::formatObject($today, $pattern, "de_DE"), "\n";
 
$dtpg = new \IntlDatePatternGenerator("en_US");
$pattern = $dtpg->getBestPattern($skeleton), "\n";
echo "en: ", \IntlDateFormatter::formatObject($today, $pattern, "en_US"), "\n";
 
/*
de: 24.04.2021
en: 04/24/2021
*/

En el código anterior, la variable skeleton define los formatos particulares de fecha u hora a utilizar. Sin embargo, el formateador maneja el orden del resultado final.

Compatibilidad con el formato de imagen AVIF

El AVIF, o Formato de Archivo de Imagen AV1, es un formato de imagen relativamente nuevo y libre de derechos basado en el formato de codificación de vídeo AV1. Además de ofrecer una mayor compresión (y, por tanto, un menor tamaño de los archivos), también admite varias funciones, como la transparencia y el HDR, entre otras.

El formato AVIF ha sido estandarizado recientemente (8 de junio de 2021). Esto ha allanado el camino para que los navegadores, como Chrome 85+ y Firefox 86+, añadan compatibilidad con las imágenes AVIF.

La extensión de procesamiento de imágenes y GD de PHP 8.1 añade soporte para imágenes AVIF.

Sin embargo, para incluir esta funcionalidad, necesitas compilar la extensión GD con soporte AVIF. Puedes hacerlo ejecutando los siguientes comandos.

Para Debian/Ubuntu:

apt install libavif-dev

Para Fedora/RHEL:

dnf install libavif-devel

Eso instalará todas las dependencias más recientes. A continuación, puedes compilar el soporte de AVIF ejecutando la bandera --with-avif con el script . /configure.

./buildconf --force
./configure --enable-gd --with-avif

Si estás empezando un nuevo entorno desde cero, también puedes habilitar otras extensiones de PHP aquí.

Una vez instalado, puedes comprobar si el soporte de AVIF está activado ejecutando el siguiente comando en tu terminal de PHP:

php -i | grep AVIF

Si has instalado AVIF correctamente, verás el siguiente resultado:

AVIF Support => enabled

También puedes utilizar la llamada gd_info() para obtener una lista de las características de GD, incluyendo si la funcionalidad de soporte AVIF está activada.

Esta extensión GD de PHP 8.1 actualizada también añade dos nuevas funciones para trabajar con imágenes AVIF: imagecreatefromavifimageavif. Funcionan de forma similar a sus homólogas JPEG y PNG.

La función imagecreatefromavif devuelve una instancia de GdImage a partir de una imagen AVIF dada. A continuación, puedes utilizar esta instancia para editar o convertir la imagen.

La otra función imageavif produce el archivo de imagen AVIF. Por ejemplo, puede utilizarla para convertir un JPEG en AVIF:

$image = imagecreatefromjpeg('image.jpeg');
imageavif($image, 'image.avif');

Puedes leer más sobre esta nueva función en su página de GitHub.

Nueva clave $_FILES: full_path para subir directorios

PHP mantiene un gran número de variables predefinidas para controlar varias cosas. Una de ellas es la variable $_FILES que contiene una matriz asociativa de elementos cargados a través del método HTTP POST.

La mayoría de los navegadores modernos soportan la carga de un directorio completo con campos de carga de archivos HTML. Incluso PHP <8.1 soportaba esta funcionalidad, pero con una gran advertencia. No se podía subir una carpeta con su estructura exacta de directorios o rutas relativas porque PHP no pasaba esta información al array $_FILES.

Esto cambia en PHP 8.1 con la adición de una nueva clave llamada full_path al array $_FILES. Usando estos nuevos datos, puedes almacenar rutas relativas o duplicar la estructura exacta de directorios en el servidor.

Puedes comprobar esta información mostrando la matriz $FILES mediante el comando var_dump($_FILES);.

Sin embargo, procede con precaución si utilizs esta función. Asegúrate de protegerte contra los ataques estándar de carga de archivos.

Soporte de desempaquetado de matrices para String-Keyed Arrays

PHP 7.4 ha añadido soporte para el desempaquetado de arrays con el operador de dispersión de arrays (). Actúa como una alternativa más rápida al uso de la función array_merge(). Sin embargo, esta característica estaba limitada a arrays con claves numéricas, ya que desempaquetar arrays con claves de cadena causaba conflictos al fusionar arrays con claves duplicadas.

Sin embargo, PHP 8 añadió soporte para argumentos con nombre, eliminando esta limitación. Por lo tanto, el desempaquetado de arrays ahora también soportará  stringed-key arrays utilizando la misma sintaxis:

$array = [...$array1, ...$array2];

Este ejemplo RFC ilustra cómo se maneja la fusión de arrays con claves de cadena duplicadas en PHP 8.1:

$array1 = ["a" => 1];
$array2 = ["a" => 2];
$array = ["a" => 0, ...$array1, ...$array2];
var_dump($array); // ["a" => 2]

Aquí, la clave de la cadena «a» aparece tres veces antes de la fusión a través de la descomposición de la matriz. Pero solo gana su último valor perteneciente a $array2.

Notación explícita de números octales

PHP soporta varios sistemas numéricos, incluyendo el decimal (base-10), el binario (base-2), el octal (base-8) y el hexadecimal (base-16). El sistema numérico decimal es el predeterminado.

Si quieres utilizar cualquier otro sistema numérico, tendrás que anteponer a cada número un prefijo estándar:

  • Hex: prefijo 0x (por ejemplo 17 = 0x11)
  • Binary: prefijo 0b (por ejemplo 3 = 0b11)
  • Octal: prefijo 0 (por ejemplo 9 = 011)

Puedes ver cómo el prefijo del sistema numérico octal varía del resto. Para estandarizar esta cuestión, muchos lenguajes de programación están añadiendo soporte para una notación numérica octal explícita: 0o o 0O.

A partir de PHP 8.1, puedes escribir el ejemplo mostrado arriba (es decir, el número 9 en base-10) en el sistema numérico octal como 0o11 o 0O11.

0o16 === 14; // true
0o123 === 83; // true
 
0O16 === 14; // true
0O123 === 83; // true
 
016 === 0o16; // true
016 === 0O16; // true

Además, esta nueva característica también funciona con el separador numérico literal de guión bajo introducido en PHP 7.4.

Lee más sobre esta nueva característica de PHP 8.1 en su RFC.

Soporte de los algoritmos Hash MurmurHash3 y xxHash

PHP 8.1 añade soporte para los algoritmos de hash MurmurHash3 y xxHash. No están diseñados para su uso criptográfico, pero aún así proporcionan una impresionante aleatoriedad, dispersión y unicidad de salida.

Estos nuevos algoritmos de hashing son más rápidos que la mayoría de los algoritmos de hashing existentes en PHP. De hecho, algunas de las variantes de estos algoritmos hash son más rápidas que el rendimiento de la memoria RAM.

Como PHP 8.1 también añade soporte para declarar parámetros $options específicos para cada algoritmo, puede hacer lo mismo con estos nuevos algoritmos. El valor por defecto de este nuevo argumento es []. Por lo tanto, no afectará a ninguna de nuestras funciones hash existentes.

Puedes leer más sobre estas nuevas características de PHP 8.1 en sus páginas de GitHub: MurmurHash3, xxHash, Algorithm-specific $options.

Soporte de DNS sobre HTTPS (DoH)

DNS-over-HTTPS (DoH) es un protocolo para la resolución de DNS a través del protocolo HTTPS. Al utilizar HTTPS para cifrar los datos entre el cliente y el resolvedor de DNS, DoH aumenta la privacidad y la seguridad del usuario al evitar los ataques MitM.

A partir de PHP 8.1, puedes utilizar la extensión Curl para especificar un servidor DoH. Requiere que PHP sea compilado con versiones libcurl 7.62+. Esto no es un problema para los sistemas operativos más populares, incluyendo las distros de Linux, ya que suelen incluir Curl 7.68+.

Puedes configurar la URL del servidor de DoH especificando la opción CURLOPT_DOH_URL.

$doh = curl_init('https://kinsta.com');
curl_setopt($doh, CURLOPT_DOH_URL, 'https://dns.google/dns-query');
curl_exec($doh);

En el ejemplo anterior, hemos utilizado el servidor DNS público de Google. Además, observa el uso de https:// en todas las URLs utilizadas. Asegúrete de configurar esto perfectamente, ya que no hay ningún servidor DNS por defecto al que recurrir en Curl.

También puedes elegir de una lista de servidores DoH públicos incluidos en la documentación de Curl.

Además, la referencia CURLOPT_DOH_URL de la documentación de Curl explica detalladamente cómo utilizar sus distintos argumentos.

Subida de archivos desde Stringscon CURLStringFile

La extensión Curl de PHP soporta peticiones HTTP(S) con carga de archivos. Para ello utiliza la clase CURLFile, que acepta una URI o una ruta de archivo, un tipo mime y el nombre final del archivo.

Sin embargo, con la clase CURLFile, solo se puede aceptar la ruta del archivo o URI, pero no el contenido del propio archivo. En los casos en los que ya se tenía el archivo que se cargaba en la memoria (por ejemplo, imágenes procesadas, documentos XML, PDF), había que utilizar data:// URI con codificación Base64.

Pero libcurl ya soporta una forma más sencilla de aceptar el contenido del archivo. La nueva clase CURLStringFile añade soporte precisamente para eso.

Puedes leer su página de GitHub para saber más sobre cómo está implementado en PHP 8.1.

Nueva constante MYSQLI_REFRESH_REPLICA

La extensión mysqli de PHP 8.1 añade una nueva constante llamada MYSQLI_REFRESH_REPLICA. Es equivalente a la constante existente MYSQLI_REFRESH_SLAVE.

Este cambio fue bienvenido en MySQL 8.0.23 para abordar la insensibilidad racial en el vocabulario técnico (los ejemplos más comunes incluyen «esclavo» y «maestro»).

Hay que tener en cuenta que la constante más antigua no está siendo eliminada o desaprobada. Los desarrolladores y las aplicaciones pueden seguir utilizándola. Esta nueva constante no es más que una opción para los desarrolladores y empresas que deseen dejar atrás dicha terminología.

Mejoras de rendimiento con Inheritance Cache

Inheritance Cache es una nueva adición a opcache que elimina la sobrecarga de la herencia de clases de PHP.

Las clases de PHP son compiladas y almacenadas en caché por opcache por separado. Sin embargo, ya están enlazadas en tiempo de ejecución en cada petición. Este proceso puede implicar varias comprobaciones de compatibilidad y el préstamo de métodos/propiedades/constantes de las clases padre y los traits.

En consecuencia, se tarda mucho tiempo en ejecutarlo, aunque el resultado sea el mismo para cada solicitud.

Inheritance Cache enlaza todas las clases dependientes únicas (padre, interfaces, rasgos, tipos de propiedades, métodos) y almacena los resultados en la memoria compartida opcache. Como ahora esto solo ocurre una vez, la herencia requiere menos instrucciones.

Además, elimina las limitaciones de las clases inmutables, como las constantes no resueltas, las propiedades tipadas y las comprobaciones de tipos covariantes. Así, todas las clases almacenadas en opcache son inmutables, lo que reduce aún más el número de instrucciones necesarias.

En definitiva, promete importantes beneficios de rendimiento. Dimitry Stogov, el autor de este parche, descubrió que mostraba una mejora del 8% en el programa base de Symfony «Hello, World!». No podemos esperar a probarlo en nuestros siguientes benchmarks de PHP.

Sintaxis de llamada de primera clase

PHP 8.1 añade una sintaxis de llamada de primera clase para reemplazar las codificaciones existentes que utilizan cadenas y arrays. Además de crear un Closure más limpio, esta nueva sintaxis también es accesible por las herramientas de análisis estático y respeta el ámbito declarado.

He aquí algunos ejemplos extraídos del RFC:

$fn = Closure::fromCallable('strlen');
$fn = strlen(...);
 
$fn = Closure::fromCallable([$this, 'method']);
$fn = $this->method(...)
 
$fn = Closure::fromCallable([Foo::class, 'method']);
$fn = Foo::method(...);

Aquí, todos los pares de expresiones son equivalentes. La sintaxis de triple punto () es similar a la sintaxis de desempaquetado de argumentos (...$args). Excepto que aquí, los argumentos aún no están rellenados.

Cambios en PHP 8.1

PHP 8.1 también incluye cambios en su sintaxis y características existentes. Vamos a discutirlos:

El shell interactivo de PHP requiere la extensión readline

La extensión readline de PHP permite funciones interactivas del shell como la navegación, el autocompletado, la edición y otras. Aunque viene incluida en PHP, no está activada por defecto.

Puedes acceder al shell interactivo de PHP usando la opción de línea de comandos -a de PHP CLI:

php -a

Interactive shell

php >
php > echo "Hello";
Hello
php > function test() {
php { echo "Hello";
php { }
php > test();
Hello

Antes de PHP 8.1, se podía abrir el shell interactivo usando PHP CLI incluso sin la extensión readline habilitada. Como era de esperar, las características interactivas del shell no funcionaban, haciendo que la opción -a no tuviera sentido.

En PHP 8.1 CLI, el shell interactivo sale con un mensaje de error si no se ha habilitado la extensión readline.

php -a
Interactive shell (-a) requires the readline extension.

El modo de error por defecto de MySQLi es el de las excepciones

Antes de PHP 8.1, MySQLi silenciaba por defecto los errores. Este comportamiento a menudo conducía a código que no seguía un manejo estricto de Errores/Excepciones. Los desarrolladores tenían que implementar sus propias funciones explícitas de manejo de errores.

PHP 8.1 cambia este comportamiento estableciendo el modo de reporte de errores por defecto de MySQLi para lanzar una excepción.

Fatal error: Uncaught mysqli_sql_exception: Connection refused in ...:...

Como se trata de un cambio de ruptura, para las versiones de PHP <8.1, debe establecer explícitamente el modo de manejo de errores utilizando la función mysqli_report antes de realizar la primera conexión de MySQLi. Alternativamente, puede hacer lo mismo seleccionando el valor de reporte de errores al instanciar una instancia de mysqli_driver.

La RFC sigue un cambio similar introducido en PHP 8.0.

Finales de línea personalizables para las funciones de escritura de CSV

Antes de PHP 8.1, las funciones de escritura CSV incorporadas en PHP, fputcsv y SplFileObject::fputcsv, estaban codificadas para añadir \n (o el carácter Line-Feed) al final de cada línea.

PHP 8.1 añade soporte para un nuevo parámetro llamado eol a estas funciones. Puedes usarlo para pasar un carácter de fin de línea configurable.  Por defecto, sigue utilizando el carácter \n. Por lo tanto, puede continuar usándolo en su código existente.

Para utilizar los caracteres de fin de línea se aplican las reglas estándar de escape de caracteres. Si deseas utilizar \r, \n, o \r\n como caracteres EOL, debes encerrarlos entre comillas dobles.

Aquí está la página de GitHub que sigue este nuevo cambio.

Nuevas restricciones del operador version_compare

La función version_compare() de PHP compara dos cadenas de números de versión. Esta función acepta un tercer argumento opcional llamado operator para probar una relación particular.

Aunque no está cubierto explícitamente en la documentación, antes de PHP 8.1, se podía establecer este parámetro a un valor parcial (por ejemplo, g, l, n) sin encontrar un error.

PHP 8.1 añade restricciones más estrictas al argumento operator de la función version_compare() para superar esta situación. Los únicos operadores que se pueden usar ahora son:

  • ==, =, y eq
  • !=, <>, y ne
  • > y gt
  • >= y ge
  • < y lt
  • <= y le

Se acabaron los valores parciales de los operadores.

Las funciones de codificación y descodificación de HTML utilizan ahora ENT_QUOTES | ENT_SUBSTITUTE

Las entidades HTML son representaciones textuales de caracteres que de otro modo se interpretarían como HTML. Piensa en caracteres como < y > utilizados para definir etiquetas HTML (por ejemplo, <a>, <h3>, <script>).

La entidad HTML para < es <; (símbolo menor que) y > es >; (símbolo mayor que).

Nota: Elimina el espacio entre «&» y «amp».

Puedes utilizar estas entidades HTML de forma segura en un documento HTML sin activar el motor de renderizado del navegador.

Por ejemplo, & lt;script>; se mostrará como <script> en el navegador, en lugar de ser interpretado como una etiqueta HTML.

Antes de PHP 8.1, las funciones htmlspecialchars() y htmlentities() convertían símbolos como ", < , > , y & a sus respectivas entidades HTML. Pero no convertían el carácter de comilla simple (') a su entidad HTML por defecto. Además, devolvían una cadena vacía si había un UTF-8 malformado en el texto.

En PHP 8.1., estas funciones de codificación y decodificación HTML (y sus funciones relacionadas) también convertirán los caracteres de comillas simples a su entidad HTML por defecto.

Y si el texto dado tiene caracteres inválidos, las funciones los sustituirán con un carácter de sustitución Unicode (�) en lugar de devolver una cadena vacía. PHP 8.1 logra esto cambiando las firmas de estas funciones a ENT_QUOTES | ENT_SUBSTITUTE en lugar de ENT_COMPAT por defecto.

La mayoría de los frameworks ya utilizan ENT_QUOTES como valor de bandera por defecto. Por lo tanto, no verás mucha diferencia debido a este cambio. Sin embargo, la nueva bandera ENT_SUBSTITUTE no es tan utilizada. PHP 8.1 hará que los caracteres UTF-8 inválidos sean sustituidos por el carácter � en lugar de devolver una cadena vacía.

Advertencia sobre llamadas a funciones compactas ilegales

La función compact() de PHP es muy útil. Puedes usarla para crear un array con variables usando sus nombres y valores.

Por ejemplo, considere el siguiente código:

$animal = 'Cat';
$sound = 'Meow';
$region = 'Istanbul';
compact('animal', 'sound', 'region');
// ['animal' => "Cat", 'sound' => "Meow", 'region' => "Istanbul"]

La documentación de la función compacta indica que solo aceptará parámetros de cadena o valores de matriz con valores de cadena. Sin embargo, antes de PHP 7.3, cualquier cadena que no se establezca será omitida silenciosamente.

PHP 7.3 modificó la función compact() para lanzar un aviso si se utilizan variables no definidas. PHP 8.1 da un paso más y lanza una advertencia.

Puedes leer su página de GitHub para entender cómo se produjo este cambio.

Nuevas migraciones de recursos a objetos de clase

Uno de los objetivos a largo plazo de PHP es alejarse de los recursos hacia los objetos de clase estándar.

Debido a razones históricas, los objetos de recursos se utilizan ampliamente en las aplicaciones PHP. Por lo tanto, la migración de recursos a objetos de clase debe ser lo menos perjudicial posible. PHP 8.1 migra cinco de estos recursos:

El recurso file_info migrado a los objetos finfo

La clase finfo de PHP ofrece una interfaz orientada a objetos para las funciones fileinfo. Sin embargo, el uso de las funciones finfo devuelve objetos de resource con el tipo file_info en lugar de una instancia de la propia clase finfo.

PHP 8.1 corrige esta anomalía.

Recursos IMAP migrados a objetos de clase IMAP\Connection

En línea con el objetivo de migración de recursos a objetos, la nueva clase IMAP\Connection minimiza los posibles cambios de ruptura cuando PHP modifique eventualmente los detalles de implementación de la clase.

Esta nueva clase también está declarada como final, por lo que no se puede extend.

Lee más sobre su implementación en su página de GitHub.

Los recursos de conexión FTP son ahora objetos de clase FTP\Connection

En PHP <8.1, si crea una conexión FTP con las funciones ftp_connect() o ftp_ssl_connect(), obtendrá un objeto recurso de tipo ftp.

PHP 8.1 añade la nueva clase FTP\Connection para rectificar eso. Y al igual que la clase IMAPConnection, también se declara final para evitar que se extienda.

Lee más sobre esta migración en su página de GitHub.

Identificadores de fuentes migrados a los objetos de la clase GdFont

La extensión GD de PHP proporciona la función imageloadfont() para cargar un mapa de bits definido por el usuario y devolver su identificador de fuente (un entero).

En PHP 8.1, esta función devolverá una instancia de la clase GdFont. Además, para facilitar la migración, todas las funciones que antes aceptaban un ID de recurso de imageloadfont() ahora tomarán los nuevos objetos de la clase GdFont.

Lee más sobre esta migración en su página de GitHub.

Recursos LDAP migrados a objetos

LDAP, o Protocolo Ligero de Acceso a Directorios, se utiliza para acceder a los «Servidores de Directorio». Al igual que una estructura de directorios en el disco duro, es una base de datos única que contiene datos en una estructura de árbol.

PHP incluye una extensión LDAP que aceptaba o devolvía objetos de recursos antes de PHP 8.1. Sin embargo, ahora todos han migrado sin problemas a nuevas instancias de clase. Los tipos de recursos que han sido transicionados son:

  • Recurso de ldap link a objeto de clase  \LDAP\Connection
  • Recurso de ldap result a objeto de clase \LDAP\Result
  • Recurso de ldap result entry a objeto de clase \LDAP\ResultEntry

Consulta su página de GitHub para entender mejor esta migración.

Los recursos de Pspell son ahora objetos de clase

La extensión Pspell de PHP permite comprobar la ortografía y las sugerencias de palabras.

PHP <8.1 utilizaba los tipos de objetos de recurso pspell y pspell config con un identificador entero. Estos dos objetos de recurso son ahora reemplazados por objetos de clase PSpell\Dictionary y PSpell\Config.

Al igual que las migraciones anteriores, todas las funciones de Pspell que antes aceptaban o devolvían identificadores de objetos de recursos tomarán las nuevas instancias de objetos de clase.

Consulta su página de GitHub para obtener más información.

Desaprobaciones en PHP 8.1

PHP 8.1 deja de lado muchas de sus características anteriores. La siguiente lista ofrece un breve resumen de las funcionalidades que han sido desaprobadas en PHP 8.1:

No se puede pasar null a parámetros de funciones internas no anulables

A partir de PHP 8.0, sus funciones internas aceptan silenciosamente valores null incluso para argumentos no anulables. Lo mismo no ocurre con las funciones definidas por el usuario: sólo aceptan null para argumentos anulables.

Por ejemplo, considere este uso:

var_dump(str_contains("foobar", null));
// bool(true)

Aquí, el valor null se convierte silenciosamente en una cadena vacía. Así, el resultado devuelve true.

Esta RFC pretende sincronizar el comportamiento de las funciones internas lanzando una advertencia de desaprobación en PHP 8.1.

var_dump(str_contains("foobar", null));
// Deprecated: Passing null to argument of type string is deprecated

La desaprobación se convertirá en un TypeError en la próxima versión mayor de PHP (es decir, PHP >=9.0), haciendo que el comportamiento de las funciones internas sea consistente con las funciones definidas por el usuario.

Uso restringido de $GLOBALS

La variable $GLOBALS de PHP proporciona una referencia directa a su tabla de símbolos interna. Soportar esta funcionalidad es complejo y afecta al rendimiento de las operaciones de array. Además, rara vez se utiliza.

Según la RFC, ya no se permite modificar indirectamente $GLOBALS. Este cambio es incompatible con el pasado.

El impacto de este cambio es relativamente bajo:

En los 2k paquetes más importantes de Composer he encontrado 23 casos que utilizan $GLOBALS sin desferenciarlo directamente. Basado en una inspección superficial, solo hay dos casos en los que $GLOBALS no se utiliza de forma de solo lectura.

Sin embargo, el uso de solo lectura de $GLOBALS sigue funcionando como siempre. Lo que ya no está soportado es la escritura en $GLOBALS como un todo. Como resultado, puede esperar un ligero aumento de rendimiento, especialmente cuando se trabaja con matrices ordinarias de PHP.

Declaraciones de tipos de retorno para funciones internas

PHP 8.0 permitió a los desarrolladores declarar parámetros y tipos de retorno para la mayoría de las funciones y métodos internos. Fue posible gracias a varias RFCs como Consistent type errors for internal functions, Union Types 2.0, y Mixed Type v2.

Sin embargo, hay muchos casos en los que puede faltar información de tipo. Algunos de ellos incluyen un tipo con recursos, parámetros fuera de pass-by-ref, tipo de retorno de métodos no finales, y funciones o métodos que no analizan los parámetros según las reglas generales. Puedes leer los detalles exactos en su RFC.

Esta RFC solo aborda el problema del tipo de retorno de los métodos no finales. Sin embargo, en lugar de eliminarlo por completo inmediatamente, el equipo de PHP proporciona una ruta de migración gradual para actualizar sus bases de código con los tipos de retorno de métodos relevantes.

Los tipos de retorno de métodos internos no finales – cuando son posibles – se declaran de forma tentativa en PHP 8.1, y se harán efectivos en PHP 9.0. Significa que en las versiones de PHP 8.x, se levanta un aviso de «obsoleto» durante las comprobaciones de herencia cuando un método interno es sobrescrito de forma que los tipos de retorno son incompatibles, y PHP 9.0 hará que estos sean un error fatal.

Si ves este aviso de desaprobación después de actualizar a PHP 8.1, asegúrate de actualizar los tipos de retorno de sus métodos.

Interfaz serializable desaprobada

PHP 7.4 introdujo el mecanismo de serialización de objetos personalizado con dos nuevos métodos mágicos: __serialize() y __unserialize(). Estos nuevos métodos tienen como objetivo reemplazar la interfaz Serializable rota eventualmente.

Esta RFC propone finalizar esa decisión estableciendo un plan para la eventual eliminación de Serializable.

En PHP 8.1, si se implementa la interfaz Serializable sin implementar los métodos __serialize() y __unserialize(), PHP lanzará una advertencia de «Deprecated».

Deprecated: The Serializable interface is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in ... on line ...

Si estás soportando PHP <7.4 y PHP >=7.4, deberías implementar tanto la interfaz Serializable como los nuevos métodos mágicos. En versiones de PHP >=7.4, los métodos mágicos tendrán prioridad.

Conversiones de float a int no compatibles, desaprobadas

PHP es un lenguaje dinámicamente tipado. Como tal, hay muchos casos en los que la coerción de tipos ocurre naturalmente. La mayoría de estas coerciones son inofensivas y súper convenientes.

Sin embargo, cuando un número flotante se convierte en un número entero, a menudo supone una pérdida de datos. Por ejemplo, cuando el flotante 3,14 se convierte en un entero 3, pierde su valor fraccionario.

Lo mismo ocurre cuando el flotador está fuera del rango de enteros de la plataforma, o cuando una cadena de flotadores se convierte en un entero.

PHP 8.1 rectifica este comportamiento y pone su coerción de tipos dinámicos más en línea con la mayoría de los lenguajes de programación modernos. El objetivo es que dichas coacciones sean predecibles e intuitivas.

En PHP 8.1, verás un aviso de desaprobación cuando un float no compatible es coaccionado implícitamente a un int. ¿Pero qué es un flotador compatible con enteros? La RFC responde a esto:

Se dice que un flotador es compatible con los enteros si posee las siguientes características:

  • Es un número (es decir, no es NaN o Infinito)
  • Está en el rango de un entero PHP (depende de la plataforma)
  • No tiene parte fraccionaria

Este aviso de desaprobación se actualizará a un TypeError en la próxima versión mayor de PHP (es decir, PHP 9.0).

El método mysqli::get_client_info y mysqli_get_client_info($param) están desaprobados

La API del cliente de MySQL define dos constantes: client_info (una cadena) y client_version (un int). El controlador nativo de MySQL (MySQLnd) es parte del código fuente oficial de PHP y vincula estas constantes a la versión de PHP. En libmysql, representan la versión de la biblioteca cliente en el momento de la compilación.

Antes de PHP 8.1, mysqli exponía estas constantes de 4 maneras: propiedades de mysqli_driver, propiedades de mysqli, función mysqli_get_client_info(), y método mysqli::get_client_info. Sin embargo, no hay un método para client_version.

MySQLnd expone estas constantes de 2 maneras a PHP: una constante y una llamada a una función. Para unificar los métodos de acceso de mysqli con estas mismas dos opciones, PHP 8.1 está dejando de lado estas otras dos opciones:

  • get_client_info en la clase mysqli. En su lugar, puede utilizar la función mysqli_get_client_info().
  • mysqli_get_client_info() con parámetros. Llame a la función sin ningún parámetro para evitar el aviso de desaprobación.

Lee más sobre esta eliminación en su página de GitHub.

Todas las funciones mhash*() (extensión hash) están desaprobadas

PHP 5.3 integró las funciones mhash*() en ext/hash como una capa de compatibilidad para ext/mhash. Posteriormente, PHP 7.0 eliminó ext/mhash.

A diferencia de las funciones hash_*(), las funciones mhash*() no están siempre disponibles. Tienes que habilitarlas por separado mientras configura PHP.

En PHP 7.4, la extensión hash fue incluida junto con PHP, haciéndola una extensión por defecto para PHP. Sin embargo, todavía soportaba la opción --enable-mhash por razones de compatibilidad.

El equipo de PHP ha decidido desaprobar las funciones mhash*() en PHP 8.1, y eliminarlas por completo en PHP 9.0. Las funciones obsoletas son mhash(), mhash_keygen_s2k(), mhash_count(), mhash_get_block_size() y mhash_get_hash_name(). Puedes utilizar la funcionalidad estándar de ext/hash en lugar de ellas.

Ajustes INI filter.default y filter.default_options desaprobados

La configuración INI filter.default de PHP permite aplicar un filtro a todos los superglobales de PHP, es decir, a los datos de GPCRS ($_GET, $_POST, $_COOKIE, $_REQUEST, y $_SERVER).

Por ejemplo, puedes establecer filter.default=magic_quotes o filter.default=add_slashes (según la versión de PHP) para resucitar la controvertida e insegura función de comillas mágicas de PHP (eliminada en PHP 5.4).

El ajuste INI filter.default proporciona una funcionalidad adicional al permitir muchos más filtros, lo que lo hace aún peor. Por ejemplo, su otra opción – filter.default=special_chars – permite las comillas mágicas solo para HTML. Hay mucho menos conocimiento de estos ajustes.

PHP 8.1 lanzará una advertencia de desaprobación si filter.default se establece a cualquier valor que no sea unsafe_raw (el predeterminado). No verás ningún aviso de desaprobación separado para filter.default_options, pero PHP 9.0 eliminará ambas configuraciones INI.

Como alternativa, puedes empezar a utilizar la función filter_var(). Ésta filtra las variables con el filtro especificado.

Desaprobar la autovivification en falso

PHP permite la autovivencia (autocreación de arrays a partir de valores falsos). Esta característica es súper útil si la variable es indefinida.

Sin embargo, no es ideal autocrear un array cuando el valor es falso o nulo.

Esta RFC desestima la autovivencia a partir de valores falsos. Sin embargo, ten en cuenta que la autovivencia a partir de variables indefinidas y nulas sigue estando permitida.

En PHP 8.1, añadir a una variable de tipo false emitirá un aviso de desaprobación:

Deprecated: Automatic conversion of false to array is deprecated in

PHP 9.0 lanzará un error fatal por lo mismo, que es idéntico a otros tipos escalares.

La propiedad mysqli_driver->driver_version está obsoleta

La propiedad mysqli_driver->driver_version de la extensión MySQLi no ha sido actualizada desde hace 13 años. A pesar de los muchos cambios en el controlador desde entonces, todavía devuelve el valor de la versión antigua del controlador, haciendo que esta propiedad no tenga sentido.

En PHP 8.1, la propiedad mysqli_driver->driver_version está obsoleta.

Otros cambios menores

Hay muchas más desaprobaciones en PHP 8.1. Enumerarlas todas aquí sería un ejercicio agotador. Te recomendamos que consultes directamente la RFC para estas desaprobaciones menores.

La página de GitHub de PHP también incluye una guía de NOTAS DE ACTUALIZACIÓN a PHP 8.1. En ella se enumeran todos los cambios de última hora que debes tener en cuenta antes de actualizar a PHP 8.1.

Summary

PHP 8.1 es mejor que su predecesor, lo que no es poco. Creemos que las características más interesantes de PHP 8.1 son los Enums, las Fibras, los Tipos Puros de Intersección y sus muchas mejoras de rendimiento. Además, estamos impacientes por poner a prueba PHP 8.1 y comparar varios frameworks y CMS de PHP.

Asegúrate de marcar esta entrada del blog para su futura referencia.

¿Qué característica de PHP 8.1 es tu favorita? Comparte tu opinión con la comunidad en la sección de comentarios más abajo.

Salman Ravoof

Salman Ravoof es desarrollador web autodidacta, escritor, creador y un gran admirador del Software Libre y de Código Abierto (FOSS, Free and Open Source Software). Además de la tecnología, le apasionan la ciencia, la filosofía, la fotografía, las artes, los gatos y la comida. Obtén más información sobre él en su sitio web, y conecta con Salman en X.