Numerosos errores fatales y recuperables han sido convertidos en excepciones en PHP 7. Estas excepciones de error heredan de la clase Error, que a su vez implementa la interfaz Throwable (la nueva interfaz base de la que todas las excepciones heredan).
Esto significa que los manejadores de errores personalizados pueden no ser invocados ya que las excepciones pueden ser lanzadas en su lugar (provocando nuevos errores irrecuperables para las excepciones Error no interceptadas).
Una descripción más completa de cómo funcionan los errores en PHP 7 se encuentra en la página de errores de PHP 7. Esta guía de migración simplemente enumerará los cambios que afectan la retrocompatibilidad.
El código que implementa un manejador de excepciones inscrito con set_exception_handler() usando una declaración de tipo Exception provocará un error fatal cuando un objeto Error es lanzado.
Si el manejador debe funcionar tanto con PHP 5 como con 7, debería eliminar la declaración de tipo del manejador, mientras que el código que se migra para funcionar exclusivamente en PHP 7 puede simplemente reemplazar la declaración de tipo Exception por Throwable.
<?php
// Código para PHP 5 que fallará.
function handler(Exception $e) { /* ... */ }
set_exception_handler('handler');
// Compatible con PHP 5 y 7.
function handler($e) { /* ... */ }
// Solo PHP 7.
function handler(Throwable $e) { /* ... */ }
?>
Anteriormente, algunas clases internas devolvían null
o un objeto
inutilizable cuando el constructor fallaba. Todas las clases internas
lanzarán ahora una Exception en este caso de la
misma manera que las clases de usuario.
Los errores del analizador ahora lanzan un objeto ParseError.
El manejo de errores para eval() ahora debe incluir
un bloque catch
que pueda manejar este error.
Todos los avisos E_STRICT
han sido reclasificados a otros niveles.
La constante E_STRICT
se conserva, por lo que las llamadas como
error_reporting(E_ALL|E_STRICT)
no provocarán errores.
Situación | Nuevo nivel/comportamiento |
---|---|
Indexación por un recurso | E_NOTICE |
Métodos estáticos abstractos | Aviso eliminado, no dispara ningún error |
"Redefinir" un constructor | Aviso eliminado, no dispara ningún error |
Incompatibilidad de firma durante la herencia | E_WARNING |
Misma propiedad (compatible) en dos rasgos usados | Aviso eliminado, no dispara ningún error |
Acceso a una propiedad estática de manera no estática | E_NOTICE |
Solo las variables deben ser asignadas por referencia | E_NOTICE |
Solo las variables deben ser pasadas por referencia | E_NOTICE |
Llamada a métodos no estáticos de manera estática | E_DEPRECATED |
PHP 7 ahora utiliza un árbol de sintaxis abstracta al analizar los archivos fuente. Esto ha permitido numerosas mejoras en el lenguaje que anteriormente eran imposibles debido a las limitaciones en el analizador utilizado en versiones anteriores de PHP, pero ha llevado a la eliminación de algunos casos especiales por razones de consistencia, lo que ha roto la retrocompatibilidad. Estos casos se detallan en esta sección.
El acceso indirecto a variables, propiedades y métodos ahora se evaluará estrictamente en orden de izquierda a derecha, en contraste con la combinación anterior de casos especiales. La tabla a continuación muestra cómo ha cambiado el orden de evaluación.
Expresión | Interpretación PHP 5 | Interpretación PHP 7 |
---|---|---|
$$foo['bar']['baz']
|
${$foo['bar']['baz']}
|
($$foo)['bar']['baz']
|
$foo->$bar['baz']
|
$foo->{$bar['baz']}
|
($foo->$bar)['baz']
|
$foo->$bar['baz']()
|
$foo->{$bar['baz']}()
|
($foo->$bar)['baz']()
|
Foo::$bar['baz']()
|
Foo::{$bar['baz']}()
|
(Foo::$bar)['baz']()
|
El código que utilizaba el antiguo orden de evaluación de derecha a izquierda debe ser reescrito para usar explícitamente este orden de evaluación con llaves (ver la columna del medio anterior). Esto hará que el código sea compatible con PHP 7.x y retrocompatible con PHP 5.x.
Esto también afecta a la palabra clave global
. La sintaxis de llaves puede ser utilizada
para emular el comportamiento anterior si es necesario:
<?php
function f() {
// Válido solo en PHP 5.
global $$foo->bar;
// Válido en PHP 5 y 7.
global ${$foo->bar};
}
?>
list() ahora asignará valores a las variables en el orden en que se definen,
en lugar de en orden inverso. En general, esto solo afecta al caso en que list()
se usa en conjunción con el operador de array []
, como se ilustra a continuación:
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
Salida del ejemplo anterior en PHP 5:
array(3) { [0]=> int(3) [1]=> int(2) [2]=> int(1) }
Salida del ejemplo anterior en PHP 7:
array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
En general, se recomienda no depender del orden en que ocurren las asignaciones de la función list(), ya que es un detalle de implementación que puede cambiar nuevamente en el futuro.
Las construcciones de list() ya no pueden estar vacías. Los siguientes elementos ya no están permitidos:
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() ya no puede descomponer variables de string. Debe usarse str_split() en su lugar.
El orden de los elementos en un array ha cambiado cuando estos elementos fueron creados automáticamente al referenciarlos en una asignación por referencia. Por ejemplo:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
Salida del ejemplo anterior en PHP 5:
array(2) { ["b"]=> &int(1) ["a"]=> &int(1) }
Salida del ejemplo anterior en PHP 7:
array(2) { ["a"]=> &int(1) ["b"]=> &int(1) }
En PHP 5, el uso de paréntesis redundantes alrededor de un argumento de función podía silenciar las advertencias de normas estrictas cuando el argumento de función se pasaba por referencia. La advertencia ahora siempre se emite.
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Genera una advertencia en PHP 7.
squareArray((getArray()));
?>
El resultado del ejemplo sería:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
Se han realizado cambios menores en el comportamiento de la estructura de control foreach, principalmente en la gestión del puntero interno del array y la modificación del array mientras se recorre.
Antes de PHP 7, el puntero interno del array se modificaba mientras se recorría un array con foreach. Esto ya no es el caso, como se muestra en el siguiente ejemplo:
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
Salida del ejemplo anterior en PHP 5:
int(1) int(2) bool(false)
Salida del ejemplo anterior en PHP 7:
int(0) int(0) int(0)
Al utilizar el modo predeterminado (por valor), foreach ahora trabaja sobre una copia del array en lugar del array original. Esto significa que los cambios realizados en el array mientras se recorre no afectarán los valores que se están iterando.
Al recorrer un array por referencia, foreach ahora identifica mejor los cambios realizados en el array durante la iteración. Por ejemplo, si se añaden valores a un array mientras se recorre, estos nuevos valores también serán iterados:
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
Salida del ejemplo anterior en PHP 5:
int(0)
Salida del ejemplo anterior en PHP 7:
int(0) int(1)
La iteración de un objeto no-Traversable ahora es idéntica a la iteración de un array por referencia. Como resultado, la mejora en el comportamiento cuando se modifica un array durante su iteración también se aplica cuando se añaden o eliminan propiedades de un objeto.
Anteriormente, los literales octales que contenían números no válidos
eran truncados silenciosamente (0128
se interpretaba como
012
). Ahora, un literal octal no válido provocará
un error de análisis.
Los desplazamientos de bits por números negativos ahora lanzarán una ArithmeticError:
<?php
var_dump(1 >> -1);
?>
Salida del ejemplo anterior en PHP 5:
int(0)
Salida del ejemplo anterior en PHP 7:
Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2 Stack trace: #0 {main} thrown in /tmp/test.php on line 2
Los desplazamientos de bits (en ambos sentidos) más allá del ancho de bits de un int siempre devolverán 0. Anteriormente, el comportamiento de estos desplazamientos dependía de la arquitectura.
Anteriormente, cuando se utilizaba 0 como divisor en los operadores de
división (/) o módulo (%), se emitía un E_WARNING y se devolvía false
.
Ahora, el operador de división devuelve un float como +INF, -INF o NAN, según lo
especificado por IEEE 754. La advertencia E_WARNING del operador de módulo ha sido
eliminada y ahora lanzará una excepción DivisionByZeroError.
<?php
var_dump(3/0);
var_dump(0/0);
var_dump(0%0);
?>
Salida del ejemplo anterior en PHP 5:
Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false) Warning: Division by zero in %s on line %d bool(false)
Salida del ejemplo anterior en PHP 7:
Warning: Division by zero in %s on line %d float(INF) Warning: Division by zero in %s on line %d float(NAN) PHP Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %s line %d
Las string que contienen números hexadecimales ya no se consideran numéricas. Por ejemplo:
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
Salida del ejemplo anterior en PHP 5:
bool(true) bool(true) int(15) string(2) "oo"
Salida del ejemplo anterior en PHP 7:
bool(false) bool(false) int(0) Notice: A non well formed numeric value encountered in /tmp/test.php on line 5 string(3) "foo"
filter_var() puede ser utilizado para verificar si una string contiene un número hexadecimal, y también para convertir una string de este tipo en un int:
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
throw new Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>
\u{
puede causar errores
Debido a la adición de la nueva
sintaxis
de escape de punto de código Unicode, las string que contienen un literal
\u{
seguido de una secuencia no válida provocarán un error fatal.
Para evitar esto, la barra invertida principal debe ser escapada.
Estas funciones fueron desaprobadas en PHP 4.1.0 en favor de
call_user_func() y
call_user_func_array(). También puede utilizar las
funciones variables
y/o el operador
...
.
Todas las funciones ereg
han sido eliminadas.
PCRE es una alternativa recomendada.
La función obsoleta mcrypt_generic_end() ha sido reemplazada por mcrypt_generic_deinit().
Además, las funciones obsoletas mcrypt_ecb(),
mcrypt_cbc(), mcrypt_cfb() y
mcrypt_ofb() han sido reemplazadas por el uso de
mcrypt_decrypt() con la constante apropiada
MCRYPT_MODE_*
.
Todas las funciones ext/mysql han sido eliminadas. Para más información sobre la elección de otra API MySQL, consulte elegir una API MySQL.
Todas las funciones ext/mssql
han sido eliminadas.
Los alias obsoletos datefmt_set_timezone_id() y IntlDateFormatter::setTimeZoneID() han sido eliminados y reemplazados respectivamente por datefmt_set_timezone() y IntlDateFormatter::setTimeZone().
set_magic_quotes_runtime(), así como su alias magic_quotes_runtime(), han sido eliminadas. Estaban obsoletas desde PHP 5.3.0 y sin efecto desde la eliminación de las comillas mágicas en PHP 5.4.0.
El alias obsoleto set_socket_blocking() ha sido eliminado y reemplazado por stream_set_blocking().
dl() ya no puede ser utilizado con PHP-FPM. Continúa funcionando en las SAPIs CLI y Embed.
El soporte para las fuentes PostScript Type1 ha sido eliminado de la extensión GD, lo que ha llevado a la eliminación de las siguientes funciones:
En su lugar, se recomienda utilizar las fuentes TrueType y sus funciones asociadas.
Las siguientes directivas INI han sido eliminadas porque sus funcionalidades asociadas también han sido eliminadas:
always_populate_raw_post_data
asp_tags
xsl.security_prefs
La directiva xsl.security_prefs
ha sido eliminada.
En su lugar, el método XsltProcessor::setSecurityPrefs()
debe ser llamado para controlar las preferencias de seguridad en una
base por procesador.
El resultado de la instrucción new
ya no se puede asignar a una variable
por referencia:
<?php
class C {}
$c =& new C;
?>
Salida del ejemplo anterior en PHP 5:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
Salida del ejemplo anterior en PHP 7:
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
Los siguientes nombres no pueden utilizarse para nombrar clases, interfaces o funciones:
Además, no deben utilizarse los siguientes nombres. Aunque no generan un error en PHP 7.0, están reservados para uso futuro y deben ser considerados obsoletos.
Se ha eliminado el soporte para el uso de etiquetas ASP y script para delimitar código PHP. Las etiquetas afectadas son:
Etiqueta de apertura | Etiqueta de cierre |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
Anteriormente no recomendado en PHP 5.6,
Las llamadas estáticas a un método no estático con un contexto incompatible
ahora resultarán en que el método llamado tendrá un indefinido
$this
y se emitirá una advertencia de obsolescencia.
<?php
class A {
public function test() { var_dump($this); }
}
// Nota: NO extiende A
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
Salida del ejemplo anterior en PHP 5.6:
Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8 object(B)#1 (0) { }
Salida del ejemplo anterior en PHP 7:
Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8 Notice: Undefined variable: this in /tmp/test.php on line 3 NULL
La construcción yield ya no requiere paréntesis y ha sido sustituida
por un operador asociativo derecho con prioridad entre print
y =>
. Esto puede provocar un cambio en el comportamiento:
<?php
echo yield -1;
// Antes se interpretaba como
echo (yield) - 1;
// Y ahora se interpreta como
echo yield (-1);
yield $foo or die;
// Antes se interpretaba como
yield ($foo or die);
// Y ahora se interpreta como
(yield $foo) or die;
?>
Los paréntesis pueden utilizarse para eliminar la ambigüedad en estos casos.
Ya no es posible definir dos o más parámetros de función
con el mismo nombre. Por ejemplo, la siguiente función desencadenará un
E_COMPILE_ERROR
:
<?php
function foo($a, $b, $unused, $unused) {
//
}
?>
func_get_arg(), func_get_args(), debug_backtrace() y las trazas de excepciones ya no devuelven el valor original que se pasó a un parámetro, sino que proporcionarán el valor actual (que podría haber sido modificado).
<?php
function foo($x) {
$x++;
var_dump(func_get_arg(0));
}
foo(1);?>
Salida del ejemplo anterior en PHP 5:
1
Salida del ejemplo anterior en PHP 7:
2
Ya no es posible definir dos o más bloques por defecto en
una instrucción de conmutación. Por ejemplo, la siguiente instrucción switch desencadenará
una E_COMPILE_ERROR
:
<?php
switch (1) {
default:
break;
default:
break;
}
?>
$HTTP_RAW_POST_DATA ya no está disponible. El flujo
php://input
debe ser utilizado en su lugar.
#
en los archivos INI han sido eliminados
Se ha eliminado el soporte para los comentarios con el prefijo #
en
los archivos INI. ;
(punto y coma) debe ser
utilizado en su lugar. Este cambio se aplica a los archivos php.ini, así como a los
archivos gestionados por parse_ini_file() y
parse_ini_string().
La extensión JSON ha sido reemplazada por JSOND, provocando tres incompatibilidades
BC menores. Primero, un número no debe terminar con una coma
decimal (es decir, 34.
debe ser cambiado a 34.0
o a 34
). Segundo, al usar la notación
científica, el exponente e
no debe seguir inmediatamente a un
punto decimal (es decir, 3.e3
debe ser cambiado a
3.0e3
o a 3e3
). Finalmente, una cadena vacía ya no
se considera como JSON válido.
Anteriormente, las funciones internas debían truncar silenciosamente los números
producidos a partir de restricciones de tipo float a entero cuando el número era
demasiado grande para representar un entero. Ahora, se emitirá un E_WARNING y
se devolverá null
.
Todas las funciones de predicado implementadas por manejadores de sesión
personalizados que devuelvan false
o -1
serán errores
fatales. Si se devuelve un valor de estas funciones distinto de un booleano, -1
o 0
, fallará y se emitirá un E_WARNING.
El algoritmo de clasificación interno ha sido mejorado, lo que puede resultar en un orden de clasificación diferente de los elementos que se comparaban como iguales anteriormente.
Nota:
No dependa del orden de los elementos que se comparan como iguales; podría cambiar en cualquier momento.
Las instrucciones break
y continue
fuera
de un bucle o una estructura de control switch
ahora se detectan en el momento de la compilación en lugar de la ejecución como
antes, y desencadenan un E_COMPILE_ERROR
.
Las instrucciones break
y continue
ya no permiten
que su argumento sea una constante, y desencadenan un
E_COMPILE_ERROR
.
La extensión mhash ha sido completamente integrada en la extensión Hash. Por lo tanto, ya no es posible detectar el soporte mhash con extension_loaded(); utilizar function_exists() en su lugar. Además, mhash ya no se reporta por get_loaded_extensions() y las funcionalidades relacionadas.
La directiva declare(ticks) ya no se filtra en diferentes unidades de compilación.