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.
?? 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()"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.
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"Las siguientes funciones ahora lanzan una ValueError cuando se pasa un valor de bandera o de modo no válido:
mode)case)flags)sorting_order)
Las siguientes funciones ahora lanzan una
ValueError cuando el argumento dado contiene
bytes NUL:
extension_filename)prefix)string)cwd)Las siguientes funciones ahora lanzan una ValueError para los valores fuera de rango, en lugar de limitarlos silenciosamente o permitir que desborden:
decimals
está fuera del rango de enteros.
seconds es
mayor que UINT_MAX, o
UINT_MAX / 1000 en Windows.
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:
base_convert(), bindec(), hexdec() y octdec() ahora emiten un aviso cuando no pueden convertir con precisión el número dado.
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]Ya no es posible clonar objetos variant, porque el comportamiento de la clonación estaba mal definido.
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.
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_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.
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_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).
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.
Las tablas de datos Unicode se han actualizado a Unicode 18.0.
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.
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_*.
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::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".
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:
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.
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.
"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_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.
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.
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.
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.
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.
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.
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\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.
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().
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.