Cambios incompatibles con versiones anteriores

PHP Core

foreach por referencia tras la compactación de un array

Los bucles foreach por referencia ahora pueden visitar elementos previamente omitidos tras la compactación de un array. Los punteros internos sobre elementos eliminados ahora pasan al siguiente elemento superviviente durante la copia en escritura.

Fusión de null y empty() sobre propiedades mágicas

?? y empty() sobre una propiedad mágica ya no llaman a __get() cuando __isset() ha materializado la propiedad escribiendo en la tabla de propiedades. El valor recién escrito se devuelve directamente. isset() aplicado directamente a la propiedad no se ve afectado; las formas anidadas como isset($o->p['k']) siguen el mismo camino que ??.

<?php
#[\AllowDynamicProperties]
class Example
{
    public function __isset(string $name): bool
    {
        $this->$name = 'from __isset()';
        return true;
    }

    public function __get(string $name): string
    {
        return 'from __get()';
    }
}

$example = new Example();
var_dump($example->foo ?? 'default');
// A partir de PHP 8.6.0: string(14) "from __isset()"
// Antes de PHP 8.6.0: string(12) "from __get()"

Conversión a string en array_intersect()

array_intersect() con al menos dos arrays ahora convierte los valores a strings mientras recorre sus entradas, en lugar de durante las comparaciones de la ordenación. Esto puede cambiar el número y el orden de las advertencias de conversión y de las llamadas a __toString(), la excepción de conversión que se alcanza, y el resultado para las implementaciones de __toString() con estado. Los tipos de los argumentos se validan antes de comprobar si hay arrays vacíos o de convertir valores, por lo que un argumento posterior no válido puede suprimir los efectos secundarios de conversión de arrays anteriores. Los valores no se convierten si alguno de los arrays de entrada está vacío.

Salto de página eliminado por defecto

El salto de página (\f) ahora se añade a los caracteres que trim(), rtrim() y ltrim() eliminan por defecto.

<?php
var_dump(trim("\f hello \f"));
// A partir de PHP 8.6.0: string(5) "hello"
// Antes de PHP 8.6.0: string(9) "\f hello \f"

Nuevos errores para argumentos no válidos

Las siguientes funciones ahora lanzan una ValueError cuando se pasa un valor de bandera o de modo no válido:

Las siguientes funciones ahora lanzan una ValueError cuando el argumento dado contiene bytes NUL:

Las siguientes funciones ahora lanzan una ValueError para los valores fuera de rango, en lugar de limitarlos silenciosamente o permitir que desborden:

  • number_format(), cuando decimals está fuera del rango de enteros.
  • sleep(), cuando seconds es mayor que UINT_MAX, o UINT_MAX / 1000 en Windows.
  • usleep(), cuando microseconds es mayor que UINT_MAX.

linkinfo() ahora lanza una ValueError cuando el argumento path está vacío.

setlocale() ahora lanza una ValueError cuando un nombre de configuración regional contiene bytes NUL, en lugar de truncarlo silenciosamente. Los arrays ahora solo se aceptan para el argumento locales. Pasar un array como argumento variádico de configuración regional posterior ahora lanza una TypeError. Pasar argumentos de configuración regional adicionales cuando locales es un array ahora lanza una ArgumentCountError.

Las siguientes funciones ahora lanzan una ValueError cuando el argumento filename contiene bytes NUL:

Aviso en la conversión imprecisa de números

base_convert(), bindec(), hexdec() y octdec() ahora emiten un aviso cuando no pueden convertir con precisión el número dado.

Modificadores de endianness en los nombres de formato de unpack()

unpack() ahora interpreta un < o un > que sigue inmediatamente a un código de formato como un modificador de endianness, y no como el primer carácter del nombre del elemento. Los formatos como "s<value" ahora producen la clave "value" en lugar de "<value", y "C>name" lanza una ValueError porque el código de formato C no acepta ningún modificador de endianness. Un nombre que empieza por estos caracteres no se ve afectado cuando le precede un repetidor, como en "s1<value". Véanse también los nuevos modificadores de endianness.

<?php
var_dump(unpack('s<value', "\x01\x00"));
// A partir de PHP 8.6.0: ["value" => 1]
// Antes de PHP 8.6.0: ["<value" => 1]

COM

Ya no es posible clonar objetos variant, porque el comportamiento de la clonación estaba mal definido.

cURL

La función de retrollamada registrada con CURLOPT_READFUNCTION ahora lanza una ValueError cuando devuelve un entero distinto de 0, CURL_READFUNC_ABORT o CURL_READFUNC_PAUSE.

DOM

Las propiedades documentadas anteriormente como de solo lectura (p. ej. DOMNode::$nodeType, DOMDocument::$xmlEncoding, DOMEntity::$actualEncoding, DOMEntity::$encoding, DOMEntity::$version) ahora se declaran con visibilidad asimétrica (public private(set)). Los intentos de escribir en ellas desde fuera de la clase ahora provocan Cannot modify private(set) property class::$prop from global scope en lugar del anterior error de modificación de una propiedad de solo lectura. ReflectionProperty::isWritable() también informa con exactitud sobre estas propiedades.

El acceso por índice en objetos Dom\DtdNamedNodeMap ahora devuelve null para los índices enteros negativos en lugar de devolver el primer nodo, y lanza una ValueError cuando el índice entero es mayor que PHP_INT_MAX en lugar de desbordar hacia un índice menor.

FTP

ftp_nb_fget(), ftp_nb_fput(), ftp_nb_get() y ftp_nb_put() ahora lanzan una Error cuando la conexión ya está realizando una transferencia, en lugar de emitir una advertencia y devolver false. ftp_close() ya lanza una excepción en la misma situación.

GD

imagesetstyle(), imagefilter() e imagecrop() filtran los tipos y los valores de sus argumentos de tipo array y lanzan, en consecuencia, una TypeError o una ValueError.

imageaffinematrixget() ahora impone el tipo array|float documentado para el parámetro options, incluido el comportamiento correspondiente del tipado débil y estricto.

GMP

gmp_fact() ahora lanza una ValueError si num no cabe en un unsigned long.

gmp_pow(), gmp_binomial(), gmp_root() y gmp_rootrem() ahora lanzan una ValueError si su segundo argumento no cabe en un unsigned long.

Los operadores de desplazamiento (<<, >>) y de exponenciación (**) sobre objetos GMP ahora lanzan una ValueError cuando los operandos derechos GMP están fuera del rango de unsigned long, en lugar de truncarlos silenciosamente.

El análisis de strings de enteros GMP ahora lanza una ValueError para los strings que contienen bytes NUL, en lugar de truncarlos silenciosamente.

El mensaje de la DivisionByZeroError lanzada por gmp_powm() en un módulo por cero ahora incluye el nombre de la función y el índice del argumento (modulus).

Intl

Pasar un objeto no stringable como zona horaria a las API de Intl que aceptan objetos o strings de zona horaria ahora lanza una TypeError en lugar de una Error.

IntlIterator::current() ahora devuelve null cuando se llama antes de que el iterador esté posicionado, o después de que el iterador se haya vuelto no válido, en lugar de exponer un valor indefinido.

IntlBreakIterator::getLocale() ahora lanza una ValueError cuando el tipo no es ni Locale::ACTUAL_LOCALE ni Locale::VALID_LOCALE, en lugar de devolver false.

MessageFormatter::parse() y MessageFormatter::parseMessage() ahora devuelven PHP_INT_MIN como int, en lugar de como float, en plataformas de 64 bits al analizar valores enteros.

El parámetro type de IntlBreakIterator::getPartsIterator() ha pasado de string a int para coincidir con la implementación subyacente.

UConverter::transcode() ahora rechaza los valores de las opciones from_subst y to_subst de más de 127 bytes, en lugar de truncar silenciosamente la longitud antes de pasarla a ICU.

ResourceBundle::get() y resourcebundle_get() ahora informan de las búsquedas de recursos con la reserva desactivada con without fallback to locale en lugar del mensaje mal formado without fallback from to locale.

IntlDateFormatter::parse()/datefmt_parse() e IntlDateFormatter::localtime()/datefmt_localtime() ahora lanzan una TypeError cuando el argumento offset no es de tipo int, en lugar de convertir silenciosamente el valor.

Collator::sort(), collator_sort(), Collator::asort() y collator_asort() ahora informan de los fallos de conversión UTF-8/UTF-16 durante la comparación a través del mecanismo de errores de intl y devuelven false. Con intl.use_exceptions activado, estos fallos lanzan una IntlException. Anteriormente, estas rutas emitían una advertencia y comparaban el valor como un string vacío.

MBString

Las tablas de datos Unicode se han actualizado a Unicode 18.0.

PCNTL

pcntl_alarm() ahora lanza una ValueError si el argumento seconds es menor que cero o mayor que el valor UINT_MAX de la plataforma.

pcntl_exec() ahora lanza una ValueError si el argumento args no es un array de tipo lista.

PCRE

preg_grep() ahora devuelve false en lugar de un array parcial cuando se produce un error de ejecución de PCRE (p. ej., una entrada UTF-8 mal formada con el modificador u). Esto es coherente con el resto de funciones preg_*.

PGSQL

Cuando se proporciona a pg_fetch_object() un parámetro constructor_args no vacío para una clase sin constructor, la ValueError ahora hace referencia al argumento constructor_args en lugar de a class. Los errores lanzados cuando la clase solicitada no es instanciable (abstracta, interfaz, enumeración) ahora aparecen antes de recuperar la fila.

Phar

Phar::mungServer() ahora lanza una ValueError cuando se pasa un valor de argumento no válido, en lugar de ignorarse silenciosamente.

Phar::addEmptyDir() ahora rechaza las rutas "/.phar" además de las rutas ".phar", y lanza la misma BadMethodCallException ante los intentos de crear el directorio mágico reservado ".phar" por esa vía. Los nombres no mágicos que simplemente comparten el prefijo ".phar" ahora se tratan como directorios ordinarios.

Los ficheros solo se interpretan automáticamente como archivos Phar al incluirse si ".phar" aparece como extensión en el componente de nombre de fichero de sus rutas. Anteriormente, podía aparecer en un nombre de directorio o como parte de una extensión como ".pharma".

Session

Definir session.cookie_path, session.cookie_domain o session.cache_limiter con un valor que contenga bytes NUL ahora emite una advertencia y deja el ajuste sin cambios. Anteriormente, los bytes NUL se aceptaban silenciosamente: para cookie_path y cookie_domain esto hacía que la SAPI descartara la cabecera Set-Cookie; para cache_limiter el valor se truncaba silenciosamente en el byte NUL.

session_module_name() ahora lanza una ValueError si name es un string que contiene bytes NUL.

session_encode() ahora devuelve un string vacío en lugar de false para las sesiones vacías. Ahora solo devuelve false cuando los datos de sesión no han podido codificarse. Esto ocurre principalmente con el gestor de serialización por defecto si una clave contiene el carácter de barra vertical (|).

Cuando session.lazy_write está activado y un gestor de sesión implementa SessionUpdateTimestampHandlerInterface, las sesiones que se leyeron como vacías y siguen vacías en el momento de la escritura ahora activarán SessionUpdateTimestampHandlerInterface::updateTimestamp() en lugar de SessionHandlerInterface::write(). Anteriormente, SessionHandlerInterface::write() se llamaba siempre para las sesiones vacías porque session_encode() devolvía false, eludiendo la comparación de lazy_write. Los gestores de sesión personalizados que dependan de que SessionHandlerInterface::write() se llame con datos vacíos (p. ej., para destruir la sesión) deberían implementar la misma lógica en su método SessionUpdateTimestampHandlerInterface::updateTimestamp().

Los valores por defecto de tres ajustes INI de sesión han cambiado para proporcionar un comportamiento seguro desde el primer momento:

  • session.use_strict_mode ahora vale 1 (antes 0). El modo estricto rechaza los identificadores de sesión no inicializados, mitigando la fijación de sesión. Los gestores de sesión personalizados que antes dependían de aceptar identificadores proporcionados externamente sin una entrada de almacenamiento correspondiente deben implementar SessionUpdateTimestampHandlerInterface::validateId() y SessionIdInterface::create_sid(), o bien definir explícitamente este ajuste en 0.
  • session.cookie_httponly ahora vale 1 (antes 0). Las cookies de sesión ya no son accesibles para JavaScript mediante document.cookie. Las aplicaciones que leen la cookie de sesión desde JavaScript deben definir explícitamente este ajuste en 0.
  • session.cookie_samesite ahora vale "Lax" (antes sin definir). Las cookies de sesión ya no se envían en peticiones entre sitios distintas de las navegaciones de nivel superior que utilizan métodos HTTP seguros. Las aplicaciones que dependen de que las cookies de sesión se envíen en envíos POST entre sitios deben definir explícitamente este ajuste en "None" (y definir también session.cookie_secure en 1).

Se ha añadido SessionHandler::validateId(), que delega en el gestor de guardado configurado. Una subclase que declara SessionHandler::validateId() sin tipo de retorno ahora emite un aviso de obsolescencia por el tipo de retorno bool provisional. Una subclase que sobrescribe SessionHandler::open() sin llamar a parent::open() mantiene su comportamiento anterior y emite una advertencia cuando se valida un identificador.

Shmop

shmop_open() ahora lanza una ValueError cuando el argumento key está fuera del rango key_t de la plataforma, en lugar de pasar una clave truncada al sistema operativo.

SimpleXML

SimpleXMLElement::__construct() ahora lanza una ValueError cuando el argumento data contiene bytes NUL, igual que simplexml_load_file(). Con dataIsURL definido, anteriormente truncaba la ruta en el primer byte NUL. Sin él, el string iba a libxml, que con las opciones por defecto rechaza un NUL en las versiones actuales pero acepta el documento truncado en versiones anteriores y con LIBXML_RECOVER.

SOAP

La opción "classmap" de SoapClient y SoapServer ahora rechaza los arrays que contienen claves enteras. Anteriormente, podían aceptarse arrays dispersos con claves enteras y arrays con claves mixtas. SoapClient ahora lanza una TypeError para las opciones "classmap" que no son arrays y una ValueError para los arrays que contienen claves enteras, también cuando la opción "exceptions" está desactivada.

El análisis de WSDL/esquemas XML ahora rechaza los valores enteros fuera de rango para las restricciones de ocurrencia y las facetas de restricción de enteros. Los valores negativos de minOccurs y maxOccurs también se rechazan.

Los errores de codificación SOAP ahora informan del tipo afectado o de la operación fallida en el mensaje de error, en lugar del mensaje genérico Encoding: Violation of encoding rules. El código que compare el mensaje exacto puede necesitar actualizarse.

Sockets

socket_set_option() con SO_ATTACH_REUSEPORT_CBPF ahora requiere un value de tipo int y un level igual a SOL_SOCKET. Cualquier otro tipo de valor lanza una TypeError en lugar de convertirse, y cualquier otro nivel emite una advertencia y devuelve false.

socket_set_option() con SO_ATTACH_REUSEPORT_CBPF y un value igual a 0 ahora desvincula el filtro reuseport mediante SO_DETACH_REUSEPORT_BPF. Anteriormente utilizaba SO_DETACH_BPF, un alias de SO_DETACH_FILTER, que dejaba el programa reuseport vinculado.

Sodium

Las funciones de hash de contraseñas sodium_crypto_pwhash(), sodium_crypto_pwhash_str(), sodium_crypto_pwhash_scryptsalsa208sha256() y sodium_crypto_pwhash_scryptsalsa208sha256_str() ahora lanzan una ValueError en lugar de una SodiumException cuando un argumento está fuera de rango, como un opslimit o un memlimit por debajo del mínimo documentado. SodiumException se sigue lanzando ante fallos internos de libsodium.

SPL

Las implementaciones de SplObjectStorage::getHash() ya no pueden modificar ninguna instancia de SplObjectStorage. Intentarlo ahora lanza una Error.

SplFileObject::next() ahora avanza el flujo cuando ninguna llamada previa a SplFileObject::current() ha almacenado una línea en caché. Una llamada posterior a SplFileObject::current() devuelve la nueva línea en lugar de la anterior.

SplFileObject::fgets() ya no almacena en caché la línea devuelta para las llamadas posteriores a SplFileObject::current(). SplFileObject::current() ahora vuelve a leer desde la posición actual del flujo en lugar de devolver la línea que SplFileObject::fgets() acaba de devolver.

SplFileObject::next() más allá del final del fichero (EOF) ya no incrementa SplFileObject::key() sin límite. SplFileObject::seek() más allá de EOF ahora produce el mismo valor de SplFileObject::key() que SplTempFileObject; anteriormente ambos devolvían valores diferentes.

DirectoryIterator::key() ahora devuelve int|string, y DirectoryIterator::current() devuelve string|SplFileInfo|static.

Sysvshm

shm_attach() ahora lanza una ValueError cuando el argumento key está fuera del rango key_t de la plataforma, en lugar de pasar una clave truncada al sistema operativo.

URI

Uri\WhatWg\Url::__construct() ahora define softErrors como un array vacío cuando el procesamiento de la URL lanza una excepción, en lugar de conservar su valor. Los errores de validación de la URL siguen disponibles en la propiedad Uri\WhatWg\InvalidUrlException::$errors.

Uri\WhatWg\Url::__construct(), Uri\WhatWg\Url::parse(), los métodos Uri\WhatWg\Url::with*() y Uri\WhatWg\UrlBuilder::build() ahora informan de los errores de validación en el orden en que se detectan. Esto invierte el orden de varios errores respecto a PHP 8.5.

Zip

ZipArchive::extractTo() ahora lanza una TypeError para el argumento files si una o más de las entradas no es un string.

ZipArchive::addGlob() y ZipArchive::addPattern() ahora lanzan una TypeError cuando la opción "remove_all_path" no es de tipo bool, o cuando las opciones "comp_method", "comp_flags" o "enc_method" no son de tipo int (los strings numéricos se convierten), en lugar de emitir una advertencia.

Serializar o deserializar una ZipArchive ahora lanza una Exception. Una subclase puede sobrescribir __serialize() y __unserialize() para realizar un recorrido de ida y vuelta mediante ZipArchive::closeString() y ZipArchive::openString().

Zlib

deflate_init() ahora lanza una TypeError cuando el valor de la opción "level", "memory", "window" o "strategy" no es de tipo int.

inflate_init() ahora lanza una TypeError cuando el valor de la opción "window" no es de tipo int.

+add a note

User Contributed Notes

There are no user contributed notes for this page.