Cambios incompatibles hacia atrás

PHP Core

Comparación de cadenas con números

Las comparaciones no estrictas entre números y cadenas no numéricas ahora funcionan convirtiendo el número a cadena y comparando las cadenas. Las comparaciones entre números y cadenas numéricas continúan funcionando como antes. En particular, esto significa que 0 == "not-a-number" ahora se considera falso.

Comparación Antes Después
0 == "0" true true
0 == "0.0" true true
0 == "foo" true false
0 == "" true false
42 == " 42" true true
42 == "42foo" true false

Otros cambios incompatibles

  • match es ahora una palabra reservada.

  • Los fallos de aserción ahora lanzan una excepción por defecto. Si se desea el comportamiento anterior, se puede establecer assert.exception=0 en la configuración INI.

  • Los métodos con el mismo nombre que la clase ya no se interpretan como constructores. Se debe usar el método __construct() en su lugar.

  • La posibilidad de llamar a métodos no estáticos de forma estática ha sido eliminada. Por lo tanto, is_callable() fallará al verificar un método no estático con un nombre de clase (se debe verificar con una instancia de objeto).

  • Las conversiones (real) y (unset) han sido eliminadas.

  • La directiva ini track_errors ha sido eliminada. Esto significa que php_errormsg ya no está disponible. Se puede usar la función error_get_last() en su lugar.

  • La posibilidad de definir constantes insensibles a mayúsculas y minúsculas ha sido eliminada. El tercer argumento de define() ya no puede ser true.

  • La posibilidad de especificar un autocargador utilizando una función __autoload() ha sido eliminada. Se debe usar spl_autoload_register() en su lugar.

  • El argumento errcontext ya no se pasará a los manejadores de errores personalizados establecidos con set_error_handler().

  • create_function() ha sido eliminada. Se pueden usar funciones anónimas en su lugar.

  • each() ha sido eliminada. Se debe usar foreach o ArrayIterator en su lugar.

  • La posibilidad de desvincular this de closures que fueron creadas a partir de un método, utilizando Closure::fromCallable() o ReflectionMethod::getClosure(), ha sido eliminada.

  • La posibilidad de desvincular this de closures propias que contienen usos de this también ha sido eliminada.

  • La posibilidad de usar array_key_exists() con objetos ha sido eliminada. Se puede usar isset() o property_exists() en su lugar.

  • El comportamiento de array_key_exists() en relación con el tipo del parámetro key se ha hecho consistente con isset() y el acceso normal a arrays. Todos los tipos de clave ahora usan las coerciones habituales y las claves de tipo array/object lanzan un TypeError.

  • Cualquier array que tenga un número n como su primera clave numérica usará n+1 para su siguiente clave implícita, incluso si n es negativo.

  • El nivel predeterminado de error_reporting es ahora E_ALL. Anteriormente excluía E_NOTICE y E_DEPRECATED.

  • display_startup_errors está ahora habilitado por defecto.

  • Usar parent dentro de una clase que no tiene padre ahora resultará en un error fatal en tiempo de compilación.

  • El operador @ ya no silenciará los errores fatales (E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_PARSE). Los manejadores de errores que esperan que error_reporting sea 0 cuando se usa @, deben ajustarse para usar una verificación de máscara en su lugar:

    <?php
    // Reemplazar
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (
    error_reporting() == 0) {
    return;
    // Silenciado
    }
    // ...
    }

    // Por
    function my_error_handler($err_no, $err_msg, $filename, $linenum) {
    if (!(
    error_reporting() & $err_no)) {
    return;
    // Silenciado
    }
    // ...
    }
    ?>

    Además, se debe tener cuidado de que los mensajes de error no se muestren en entornos de producción, lo que puede resultar en fugas de información. Es necesario asegurarse de que display_errors=Off se use junto con el registro de errores.

  • #[ ya no se interpreta como el inicio de un comentario, ya que esta sintaxis ahora se usa para atributos.

  • Los errores de herencia debidos a firmas de métodos incompatibles (violaciones de LSP) ahora siempre generarán un error fatal. Anteriormente se generaba una advertencia en algunos casos.

  • La precedencia del operador de concatenación ha cambiado en relación con los desplazamientos de bits y la suma, así como la resta.

    <?php
    echo "Sum: " . $a + $b;
    // anteriormente se interpretaba como:
    echo ("Sum: " . $a) + $b;
    // ahora se interpreta como:
    echo "Sum:" . ($a + $b);
    ?>

  • Los argumentos con un valor predeterminado que se resuelve a null en tiempo de ejecución ya no marcarán implícitamente el tipo del argumento como nullable. Se debe usar un tipo nullable explícito o un valor predeterminado null explícito en su lugar.

    <?php
    // Reemplazar
    function test(int $arg = CONST_RESOLVING_TO_NULL) {}
    // Por
    function test(?int $arg = CONST_RESOLVING_TO_NULL) {}
    // O
    function test(int $arg = null) {}
    ?>

  • Varias advertencias se han convertido en excepciones Error:

    • Intentar escribir en una propiedad de un no-objeto. Anteriormente esto creaba implícitamente un objeto stdClass para null, false y cadenas vacías.
    • Intentar agregar un elemento a un array cuya clave PHP_INT_MAX ya está en uso.
    • Intentar usar un tipo no válido (array u objeto) como clave de array u offset de cadena.
    • Intentar escribir en un índice de array de un valor escalar.
    • Intentar desempaquetar un valor que no es array/Traversable.
    • Intentar acceder a constantes no calificadas que no están definidas. Anteriormente, el acceso a constantes no calificadas resultaba en una advertencia y se interpretaban como cadenas.

    Varios avisos se han convertido en advertencias:

    • Intentar leer una variable no definida.
    • Intentar leer una propiedad no definida.
    • Intentar leer una clave de array no definida.
    • Intentar leer una propiedad de un no-objeto.
    • Intentar acceder a un índice de array de un no-array.
    • Intentar convertir un array a cadena.
    • Intentar usar un recurso como clave de array.
    • Intentar usar null, un booleano o un flotante como offset de cadena.
    • Intentar leer un offset de cadena fuera de los límites.
    • Intentar asignar una cadena vacía a un offset de cadena.

  • Intentar asignar múltiples bytes a un offset de cadena ahora emitirá una advertencia.

  • Los caracteres inesperados en los archivos fuente (como bytes NUL fuera de las cadenas) ahora resultarán en una excepción ParseError en lugar de una advertencia de compilación.

  • Las excepciones no capturadas ahora pasan por un "cierre limpio", lo que significa que los destructores se llamarán después de una excepción no capturada.

  • El error fatal en tiempo de compilación "Only variables can be passed by reference" se ha pospuesto hasta el tiempo de ejecución y se ha convertido en una excepción Error "Argument cannot be passed by reference".

  • Algunos avisos "Only variables should be passed by reference" se han convertido en la excepción "Argument cannot be passed by reference".

  • El nombre generado para las clases anónimas ha cambiado. Ahora incluirá el nombre de la primera clase padre o interfaz:

    <?php
    new class extends ParentClass {};
    // -> ParentClass@anonymous
    new class implements FirstInterface, SecondInterface {};
    // -> FirstInterface@anonymous
    new class {};
    // -> class@anonymous
    ?>

    El nombre mostrado arriba todavía va seguido de un byte NUL y un sufijo único.

  • Las referencias a métodos de trait no absolutas en las adaptaciones de alias de trait ahora deben ser inequívocas:

    <?php
    class X {
    use
    T1, T2 {
    func as otherFunc;
    }
    function
    func() {}
    }
    ?>

    Si tanto T1::func() como T2::func() existen, este código era aceptado silenciosamente antes, y se asumía que func se refería a T1::func. Ahora generará un error fatal en su lugar, y se debe escribir explícitamente T1::func o T2::func.

  • La firma de los métodos abstractos definidos en traits ahora se verifica contra el método de la clase que los implementa:

    <?php
    trait MyTrait {
    abstract private function
    neededByTrait(): string;
    }

    class
    MyClass {
    use
    MyTrait;

    // Error, debido a la incompatibilidad del tipo de retorno.
    private function neededByTrait(): int { return 42; }
    }
    ?>

  • Las funciones deshabilitadas ahora se tratan exactamente como funciones inexistentes. Llamar a una función deshabilitada la reportará como desconocida, y redefinir una función deshabilitada ahora es posible.

  • Los envoltorios de flujo data:// ya no son escribibles, lo que coincide con el comportamiento documentado.

  • Los operadores aritméticos y a nivel de bits +, -, *, /, **, %, <<, >>, &, |, ^, ~, ++, -- ahora lanzarán consistentemente un TypeError cuando uno de los operandos sea un array, resource u object no sobrecargado. La única excepción a esto es la operación de fusión de arrays +, que sigue siendo soportada.

  • La conversión de flotante a cadena ahora siempre se comportará de manera independiente de la configuración regional.

    <?php
    setlocale
    (LC_ALL, "de_DE");
    $f = 3.14;
    echo
    $f, "\n";
    // Anteriormente: 3,14
    // Ahora: 3.14
    ?>

    Véase printf(), number_format() y NumberFormatter() para formas de personalizar el formato de números.

  • El soporte para el acceso a offsets con llaves (obsoleto) ha sido eliminado.

    <?php
    // En lugar de:
    $array{0};
    $array{"key"};
    // Escribir:
    $array[0];
    $array["key"];
    ?>

  • Aplicar el modificador final en un método privado ahora producirá una advertencia a menos que ese método sea el constructor.

  • Si el constructor de un objeto llama a exit(), el destructor del objeto ya no se llamará. Esto coincide con el comportamiento cuando el constructor lanza una excepción.

  • Los nombres con espacio de nombres ya no pueden contener espacios en blanco: Mientras que Foo\Bar se reconocerá como un nombre con espacio de nombres, Foo \ Bar no. Por el contrario, las palabras reservadas ahora están permitidas como segmentos de espacio de nombres, lo que también puede cambiar la interpretación del código: new\x ahora es lo mismo que constant('new\x'), no new \x().

  • Los ternarios anidados ahora requieren paréntesis explícitos.

  • debug_backtrace() y Exception::getTrace() ya no proporcionarán referencias a los argumentos. No será posible cambiar los argumentos de una función a través del backtrace.

  • El manejo de cadenas numéricas ha sido modificado para ser más intuitivo y menos propenso a errores. Los espacios en blanco finales ahora se permiten en cadenas numéricas por consistencia con la forma en que se tratan los espacios en blanco iniciales. Esto afecta principalmente a:

    • La función is_numeric()
    • Comparaciones de cadena a cadena
    • Declaraciones de tipo
    • Operaciones de incremento y decremento

    El concepto de "cadena numéricamente inicial" ha sido mayormente eliminado; los casos donde esto se mantiene existen para facilitar la migración. Las cadenas que emitían un E_NOTICE "A non well-formed numeric value encountered" ahora emitirán un E_WARNING "A non-numeric value encountered" y todas las cadenas que emitían un E_WARNING "A non-numeric value encountered" ahora lanzarán un TypeError. Esto afecta principalmente a:

    • Operaciones aritméticas
    • Operaciones a nivel de bits

    Este cambio de E_WARNING a TypeError también afecta al E_WARNING "Illegal string offset 'string'" para offsets de cadena ilegales. El comportamiento de las conversiones explícitas a int/float desde cadenas no ha cambiado.

  • Los métodos mágicos ahora tendrán sus argumentos y tipos de retorno verificados si los tienen declarados. Las firmas deben coincidir con la siguiente lista:

    • __call(string $name, array $arguments): mixed
    • __callStatic(string $name, array $arguments): mixed
    • __clone(): void
    • __debugInfo(): ?array
    • __get(string $name): mixed
    • __invoke(mixed $arguments): mixed
    • __isset(string $name): bool
    • __serialize(): array
    • __set(string $name, mixed $value): void
    • __set_state(array $properties): object
    • __sleep(): array
    • __unserialize(array $data): void
    • __unset(string $name): void
    • __wakeup(): void

  • Las claves de array de call_user_func_array() ahora se interpretarán como nombres de parámetros, en lugar de ser silenciosamente ignoradas.

  • Declarar una función llamada assert() dentro de un espacio de nombres ya no está permitido y emite E_COMPILE_ERROR. La función assert() está sujeta a un tratamiento especial por parte del motor, lo que puede llevar a un comportamiento inconsistente al definir una función con espacio de nombres con el mismo nombre.

Migración de recursos a objetos

Varios resources han sido migrados a objects. Las comprobaciones de valores de retorno que utilizan is_resource() deben ser reemplazadas por comprobaciones de false.

COM y .Net (Windows)

La capacidad de importar constantes que no distinguen entre mayúsculas y minúsculas desde bibliotecas de tipos ha sido eliminada. El segundo argumento de com_load_typelib() ya no puede ser false; com.autoregister_casesensitive ya no puede ser deshabilitado; los marcadores que no distinguen entre mayúsculas y minúsculas en com.typelib_file son ignorados.

CURL

CURLOPT_POSTFIELDS ya no acepta objetos como arrays. Para interpretar un objeto como un array, se debe realizar una conversión explícita con (array). Lo mismo aplica para otras opciones que aceptan arrays.

Date y Time

mktime() y gmmktime() ahora requieren al menos un argumento. Se puede utilizar time() para obtener la marca de tiempo actual.

DOM

Las clases no implementadas de la extensión DOM que no tenían comportamiento y contenían datos de prueba han sido eliminadas. Estas clases también han sido eliminadas en la última versión del estándar DOM:

  • DOMNameList
  • DomImplementationList
  • DOMConfiguration
  • DomError
  • DomErrorHandler
  • DOMImplementationSource
  • DOMLocator
  • DOMUserDataHandler
  • DOMTypeInfo

Enchant

Exif

read_exif_data() ha sido eliminada; debe usarse exif_read_data() en su lugar.

Filter

GD

GMP

gmp_random() ha sido eliminada. Debe usarse gmp_random_range() o gmp_random_bits() en su lugar.

Iconv

Las implementaciones de iconv que no establecen correctamente errno en caso de errores ya no son soportadas.

IMAP

Funciones de internacionalización

  • La constante obsoleta INTL_IDNA_VARIANT_2003 ha sido eliminada.

  • La constante obsoleta Normalizer::NONE ha sido eliminada.

LDAP

MBString

OCI8

  • La clase OCI-Lob ahora se llama OCILob, y la clase OCI-Collection ahora se llama OCICollection para el cumplimiento de nombres impuesto por las herramientas de anotación de tipos arginfo de PHP 8.

  • Varias funciones alias han sido marcadas como obsoletas.

  • oci_internal_debug() y su alias ociinternaldebug() han sido eliminados.

ODBC

OpenSSL

  • openssl_seal() y openssl_open() ahora requieren que se pase el parámetro method, ya que el valor predeterminado anterior de "RC4" se considera inseguro.

Expresiones regulares (compatibles con Perl)

Al pasar secuencias de escape no válidas, estas ya no se interpretan como literales. Este comportamiento requería anteriormente el modificador X, que ahora se ignora.

PHP Data Objects

  • El modo de gestión de errores predeterminado ha sido cambiado de "silent" a "exceptions". Consulte Errores y gestión de errores para más detalles.

  • Las firmas de algunos métodos de PDO han cambiado:

    • PDO::query(string $query, ?int $fetchMode = null, mixed ...$fetchModeArgs)
    • PDOStatement::setFetchMode(int $mode, mixed ...$args)

PDO ODBC

La directiva php.ini pdo_odbc.db2_instance_name ha sido eliminada.

PDO MySQL

PDO::inTransaction() ahora informa del estado real de la transacción de la conexión, en lugar de una aproximación mantenida por PDO. Si se ejecuta una consulta sujeta a "implicit commit", PDO::inTransaction() devolverá posteriormente false, ya que la transacción ya no está activa.

PostgreSQL

  • La sintaxis obsoleta de pg_connect() que utiliza múltiples parámetros en lugar de una cadena de conexión ya no es compatible.

  • La firma obsoleta de pg_lo_import() y pg_lo_export() que pasa la conexión como último argumento ya no es compatible. La conexión debe pasarse como primer argumento.

  • pg_fetch_all() ahora devuelve un array vacío en lugar de false para conjuntos de resultados con cero filas.

Phar

Los metadatos asociados a un phar ya no se deserializan automáticamente, para corregir posibles vulnerabilidades de seguridad debidas a la instanciación de objetos, la carga automática, etc.

Reflection

  • Las firmas de los métodos

    • ReflectionClass::newInstance($args)
    • ReflectionFunction::invoke($args)
    • ReflectionMethod::invoke($object, $args)

    han sido cambiadas a:

    • ReflectionClass::newInstance(...$args)
    • ReflectionFunction::invoke(...$args)
    • ReflectionMethod::invoke($object, ...$args)

    El código que debe ser compatible tanto con PHP 7 como con PHP 8 puede utilizar las siguientes firmas para ser compatible con ambas versiones:

    • ReflectionClass::newInstance($arg = null, ...$args)
    • ReflectionFunction::invoke($arg = null, ...$args)
    • ReflectionMethod::invoke($object, $arg = null, ...$args)

  • El método ReflectionType::__toString() ahora devuelve una representación completa de depuración del tipo y ya no está obsoleto. En particular, el resultado incluirá un indicador de nulabilidad para los tipos anulables. El formato del valor de retorno no es estable y puede cambiar entre versiones de PHP.

  • Los métodos export() de Reflection han sido eliminados. En su lugar, los objetos de reflexión pueden ser convertidos a string.

  • ReflectionMethod::isConstructor() y ReflectionMethod::isDestructor() ahora también devuelven true para los métodos __construct() y __destruct() de las interfaces. Anteriormente, esto solo era cierto para los métodos de clases y traits.

  • El método ReflectionType::isBuiltin() ha sido movido a ReflectionNamedType. ReflectionUnionType no lo tiene.

Sockets

  • Las constantes obsoletas AI_IDN_ALLOW_UNASSIGNED y AI_IDN_USE_STD3_ASCII_RULES del parámetro flags de socket_addrinfo_lookup() han sido eliminadas.

Standard PHP Library (SPL)

Biblioteca estándar

  • assert() ya no evaluará argumentos de tipo string, en su lugar se tratarán como cualquier otro argumento. Se debe usar assert($a == $b) en lugar de assert('$a == $b'). La directiva ini assert.quiet_eval y la constante ASSERT_QUIET_EVAL también han sido eliminadas, ya que no tendrían ningún efecto.

  • parse_str() ya no puede utilizarse sin especificar un array de resultados.

  • El filtro string.strip_tags ha sido eliminado.

  • El argumento needle de strpos(), strrpos(), stripos(), strripos(), strstr(), strchr(), strrchr() y stristr() ahora siempre se interpretará como un string. Anteriormente, los needle que no eran string se interpretaban como un punto de código ASCII. Se puede usar una llamada explícita a chr() para restaurar el comportamiento anterior.

  • El argumento needle de strpos(), strrpos(), stripos(), strripos(), strstr(), stristr() y strrchr() ahora puede estar vacío.

  • El argumento length de substr(), substr_count(), substr_compare() y iconv_substr() ahora puede ser null. Los valores null se comportarán como si no se hubiera proporcionado el argumento de longitud y, por lo tanto, devolverán el resto del string en lugar de un string vacío.

  • El argumento length de array_splice() ahora puede ser null. Los valores null se comportarán de forma idéntica a omitir el argumento, eliminando así todo desde el offset hasta el final del array.

  • El argumento args de vsprintf(), vfprintf() y vprintf() ahora debe ser un array. Anteriormente se aceptaba cualquier tipo.

  • La opción 'salt' de password_hash() ya no es compatible. Si se usa la opción 'salt', se genera una advertencia, la sal proporcionada se ignora y se usa una sal generada automáticamente.

  • La función quotemeta() ahora devuelve un string vacío si se le pasa un string vacío. Anteriormente se devolvía false.

  • Las siguientes funciones han sido eliminadas:

  • FILTER_SANITIZE_MAGIC_QUOTES ha sido eliminada.

  • Llamar a implode() con los parámetros en orden inverso ($pieces, $glue) ya no es compatible.

  • parse_url() ahora distingue las consultas y fragmentos ausentes de los vacíos:

    • http://example.com/foo → query = null, fragment = null
    • http://example.com/foo? → query = "", fragment = null
    • http://example.com/foo# → query = null, fragment = ""
    • http://example.com/foo?# → query = "", fragment = ""
    Anteriormente, en todos los casos, query y fragment eran null.

  • var_dump() y debug_zval_dump() ahora muestran los números de punto flotante utilizando serialize_precision en lugar de precision. En una configuración predeterminada, esto significa que los números de punto flotante ahora se muestran con total precisión por estas funciones de depuración.

  • Si el array devuelto por __sleep() contiene propiedades inexistentes, estas ahora se ignoran silenciosamente. Anteriormente, tales propiedades se habrían serializado como si tuvieran el valor null.

  • La configuración regional predeterminada al inicio ahora es siempre "C". Ninguna configuración regional se hereda del entorno de forma predeterminada. Anteriormente, LC_ALL se establecía en "C", mientras que LC_CTYPE se heredaba del entorno. Sin embargo, algunas funciones no respetaban la configuración regional heredada sin una llamada explícita a setlocale(). Ahora siempre se requiere una llamada explícita a setlocale() si se desea cambiar un componente de la configuración regional respecto al valor predeterminado.

  • El respaldo obsoleto DES en crypt() ha sido eliminado. Si se pasa un formato de sal desconocido a crypt(), la función fallará con *0 en lugar de recurrir a un hash DES débil.

  • Especificar rondas fuera de rango para SHA256/SHA512 en crypt() ahora fallará con *0 en lugar de ajustar al límite más cercano. Esto coincide con el comportamiento de glibc.

  • El resultado de las funciones de ordenación puede haber cambiado si el array contiene elementos que se comparan como iguales.

  • Cualquier función que acepte callbacks que no estén especificados explícitamente para aceptar parámetros por referencia ahora emitirá una advertencia si se usa un callback con parámetros por referencia. Los ejemplos incluyen array_filter() y array_reduce(). Este ya era el caso para la mayoría, pero no todas, las funciones anteriormente.

  • El envolvente de flujo HTTP, tal como lo usan funciones como file_get_contents(), ahora anuncia HTTP/1.1 en lugar de HTTP/1.0 de forma predeterminada. Esto no cambia el comportamiento del cliente, pero puede hacer que los servidores respondan de manera diferente. Para mantener el comportamiento anterior, se debe establecer la opción de contexto de flujo 'protocol_version', p. ej.

    <?php
    $ctx
    = stream_context_create(['http' => ['protocol_version' => '1.0']]);
    echo
    file_get_contents('http://example.org', false, $ctx);
    ?>

  • Llamar a crypt() sin una sal explícita ya no es compatible. Para producir un hash fuerte con una sal generada automáticamente, se debe usar password_hash() en su lugar.

  • substr(), mb_substr(), iconv_substr() y grapheme_substr() ahora ajustan de manera consistente los desplazamientos fuera de los límites al límite del string. Anteriormente, se devolvía false en lugar del string vacío en algunos casos.

  • En Windows, las funciones de ejecución de programas (proc_open(), exec(), popen(), etc.) que usan el shell, ahora ejecutan de manera consistente %comspec% /s /c "$commandline", lo que tiene el mismo efecto que ejecutar $commandline (sin comillas adicionales).

Sysvsem

  • El parámetro auto_release de sem_get() ha sido modificado para aceptar valores bool en lugar de int.

Tidy

Tokenizer

  • Los tokens T_COMMENT ya no incluirán un salto de línea al final. El salto de línea será parte del siguiente token T_WHITESPACE. Cabe señalar que T_COMMENT no siempre va seguido de un espacio en blanco, también puede ir seguido de T_CLOSE_TAG o del final del archivo.

  • Los nombres con espacio de nombres ahora se representan utilizando los tokens T_NAME_QUALIFIED (Foo\Bar), T_NAME_FULLY_QUALIFIED (\Foo\Bar) y T_NAME_RELATIVE (namespace\Foo\Bar). T_NS_SEPARATOR solo se usa para separadores de espacio de nombres independientes, y solo es sintácticamente válido en conjunto con declaraciones de uso de grupo.

XMLReader

XMLReader::open() y XMLReader::xml() ahora son métodos estáticos. Todavía pueden llamarse como métodos de instancia, pero las clases herederas deben declararlos como estáticos si sobrescriben estos métodos.

XML-RPC

La extensión XML-RPC ha sido movida a PECL y ya no forma parte de la distribución de PHP.

Zip

ZipArchive::OPSYS_Z_CPM ha sido eliminada (el nombre era un error tipográfico). Se debe usar ZipArchive::OPSYS_CPM en su lugar.

Zlib

Paquetes de pruebas de PHP para Windows

El ejecutor de pruebas ha sido renombrado de run-test.php a run-tests.php, para coincidir con su nombre en php-src.

add a note

User Contributed Notes 2 notes

up
20
retry, abort, fail
4 years ago
The change in string to int comparison mentioned above (e.g. '' == 0 now equates to false) has some other nasty consequences:

$a = '';

// php 8

if ( $a < 0 ) echo 'true'; // echos true
if ( $a < -1) echo 'true'; // echos true
if ( $a < -100 ) echo 'true'; // echos true

// php 7

if ( $a < 0 ) echo 'true'; // no output
if ( $a < -1) echo 'true'; // no output
if ( $a < -100 ) echo 'true'; // no output

So in a situation where you may have a web form input and expected an empty value to equate to 0, watch out not only for == 0, != 0, and <= 0 comparisons, but ALL < or <= comparisons to negative integers.
up
4
aphpguy at galaxy dot za dot net
2 years ago
If you have older projects that break with PHP7 to 8 migration due to the loose comparison issue: 

i.e. if ($a == 0) different behaviour between PHP 7 and PHP 8 
(for case like $a = "" or $a = "123foo" and other cases listed at top)

replace in old code: 

if ($a == 0) { .. }  

with 

if (cmp_eq($a, $b)) { .. } 

Tested with a wide range of scenarios, even against arrays, booleans, file handles, pipe handles, objects, scalars and numbers.

So old code still behave like before.  
Then both PHP8.x and older PHP up to ver 7.x will give the exact same boolean true or false output for loose comparisons.

function cmp_eq($a, $b) {
// If both $a and $b are of type strings, compare them as strings
if (is_string($a) && is_string($b)) { return $a == $b; } // may not be === because php says '42' equals '042' true yet '42' === '042' is false.

// If both $a and $b are numeric strings, compare them as numbers
if (is_numeric($a) && is_numeric($b)) { return $a == $b; }

// If $a is an empty string and $b is 0, or vice versa, return true
if (($a === '' && $b === 0) || ($a === 0 && $b === '')) { return true; }

// If $a is a non-numeric string and $b is 0, or vice versa, return true
if ((is_string($a) && ($a !== '') && ($b === 0)) || (($a === 0) && is_string($b) && ($b !== ''))) {
return true;
}
// special case '123abc' == 123 .. php 7 casts 123abc to 123, then 123 == 123 results in true. lets mimic that.
if ((is_string($a) && ($a !== '') && (is_numeric($b)) && ((bool)$b))) {
$number = filter_var($a, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $number == $b;
}
if (is_numeric($a) && ((bool)$a) && is_string($b) && ($b !== '')) {
$number = filter_var($b, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); //"-234.56xyz"
return $a == $number;
}

// If $a is a number and $b is a non-numeric string, cast $a to string and compare
if (is_numeric($a) && is_string($b)) { return strval($a) == $b; }

// If $b is a number and $a is a non-numeric string, cast $b to string and compare
if (is_string($a) && is_numeric($b)) { return $a == strval($b); }

// If $a and $b are both non-numeric strings, compare them directly, we should return true if they are the same
return $a == $b;
} // end func cmp_eq

Note: the better way would be to port code to PHP 8, use strict variable typing and rather make use of the === and !== operators.

But in some cases having lots of old code to quickly patch, this might help.
To Top