Muchos errores fatales y errores fatales recuperables han sido convertidos en excepciones en PHP 7. Estas excepciones de error heredan de la clase Error, la cual implementa en sí la interfaz Throwable, (la interfaz base que heredan todas las excepciones).
Esto significa que los manejadores de errores personalizados podrían no desencadenarse debido a que podrían lanzarse excepciones en su lugar (causando nuevos errores fatales para excepciones Error no capturadas).
Se puede encontrar una descripción más completa de cómo operan los errores en PHP 7 en la página de errores de PHP 7. Esta guía de migración simplemente enumerará los cambios que afectan a la retrocompatiblidad.
El código que implemente un manejador de excepciones registrado con set_exception_handler() empleando una declaración de tipo de Exception causará un error fatal cuando sea lance un objeto Error.
Si el manejador necesita funcionar tanto en PHP 5 como en PHP 7, se debería eliminar la declaración de tipo del manejador, mientras que el código que sea migrado para que funcione exclusivamente en PHP 7 puede simplemente reemplazar la declaración de tipo Exception con Throwable en su lugar.
<?php
// Código de la era de PHP 5 que no funcionará.
function handler(Exception $e) { ... }
set_exception_handler('handler');
// Compatible con PHP 5 y 7.
function handler($e) { ... }
// Solo PHP 7.
function handler(Throwable $e) { ... }
?>
Previamente, algunas clases internas devolvían NULL
o un objeto inutilizable
cuando el constructor fallaba. Ahora, todas las clases internas lanzan una
Exception en tal caso, de la misma forma que las clases
de usuario ya deben de hacerlo.
Los errores de análisis ahora lanzan un objeto ParseError. El manejo de errores para eval() ahora debería incluir un bloque catch que permita manejar dicho error.
Todos los avisos de E_STRICT
han sido reclasificados a
otros niveles. Se mantiene la consntante E_STRICT
, por lo que llamadas como
error_reporting(E_ALL|E_STRICT) no ocasionarán ningún error.
Situación | Nuevo nivel/comportamiento |
---|---|
Indexación mediante un recurso | E_NOTICE |
Métodos estáticos abstractos | Aviso eliminado, no genera un error |
'Redefinición' de un constructor | Aviso eliminado, no genera un error |
Discordancia de la signatura durante la herencia | E_WARNING |
Misma propiedad (compatible) en dos rasgos empleados | Aviso eliminado, no genera un error |
Acceso a una propiedad estática de forma no estática | E_NOTICE |
Solamente las variables deberían ser asignadas por referencia | E_NOTICE |
Solamente las variables deberían ser pasadas por referencia | E_NOTICE |
Llamada a métodos no estáticos de forma estática | E_DEPRECATED |
PHP 7 ahora emplea un árbol sintáctico abstracto al analizar ficheros. Esto ha permitido muchas mejoras en el lenguaje que antes eran imposibles debido a las limitaciones del analizador empleado en versiones previas de PHP, aunque ha resultado en la eliminación de unos pocos casos especiales por razones de consistencia, dando así lugar a roturas de retrocompatibilidad. Dichos casos están detallados a continuación.
El acceso indirecto a variables, propiedades y métodos ahora se evalúa estrictamente de izquierda a derecha, en contraste a la mezcla anterior de casos especiales. La tabla de abajo muestra los cambios en el orden de evaluación.
Expresión | Interpretación de PHP 5 | Interpretación de 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 emplee el orden antiguo de evaluación de derecha a izquierda debe ser rescrito para utilizar explícitamente el orden de evaluación con llaves (véase la columna de en medio de arriba). Esto hará al código compatible con PHP 7.x y retrocompatible con PHP 5.x.
list() ahora asigna valores a variables en el orden
en el que estas se definen, en vez de en orden inverso. En general, esto solamente
afecta al caso donde list() se emplea junto
con el operador de array []
, como se muestra 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 el que ocurren las asignaciones de list(), ya que este es un detalle de implementación que podría cambiar en el futuro.
Las construcciones de list() ya no pueden estar vacías. Lo siguiente ya no es válido:
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() ya no puede desempaquetar variables de tipo string. Debería usarse str_split() en su lugar.
El orden de los elementos de un array ha cambiado cuando dichos elementos han sido creados automáticamente haciendo referencia a ellos 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) }
Ya no se pueden utilizar variables variables con la palabra reservada global. Se puede emplear la sintaxis de llaves para emular el comportamiento anterior si fuera necesario:
<?php
function f() {
// Válido solamente en PHP 5.
global $$foo->bar;
// Válido en PHP 5 y 7.
global ${$foo->bar};
}
?>
Como principio general, se desaconseja el uso de global con algo que no sea una simple variable.
En PHP 5, el uso de paréntesis redundantes alrededor de un argumento de una función podía silenciar advertencias del estándar estricto cuando el argumento de dicha función era pasado por referencia. Estas advertencias ahora se emiten siempre.
<?php
function obtenerArray() {
return [1, 2, 3];
}
function arrayAlCuadrado(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Genera una advertencia en PHP 7.
arrayAlCuadrado((obtenerArray()));
?>
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 alrededor del manejo del puntero de arrays interno y la modificación del array en su recorrido.
Antes de PHP 7, el puntero de arrays interno era modificado mientras el array se recorría con foreach. Este 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 de iteración por valor, foreach ahora opera sobre una copia del array a recorrer en lugar del array en sí. Esto significa que los cambios realizados a un array durante una iteración no afectarán a los valores que se recorren.
Cuando se itera por referencia, foreach ahora realizará un trabajo mejor realizando un seguimiento de los cambios hechos en el array durante la iteración. Por ejemplo, al añadir valores a un array mientras se recorre dará como resultado también el recorrido de los valores añadidos:
<?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)
Recorrer un objeto no Traversable ahora tendrá el mismo comportamiento que recorrer arrays por referencia. Esto resulta en que la mejora del comportamiento al modificar un array durante la iteración se aplique también cuando se añaden propiedades a o se eleminan de un objeto.
Previamente, los literales de octal que contenían números inválidos eran truncados silenciosamente (0128 era tomado como 012). Ahora, un literal de octal inválido causará un error de análisis.
Los desplazamientos de bit mediante números negativos ahora lanzan un 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 cualquier dirección) fuera del ancho de bit de un integer siempre resultarán en 0. Anteriormente, el comportamiento de dichos desplazamientos dependía de la arquitectura.
Anteriormente, cuando se empleaba 0 como divisor de los operadores de
división (/) o módulo (%), se emitía un error de tipo E_WARNING y
se devolvía false
. Ahora, el operador de división
devuelve un valor de tipo float así como +INF, -INF, o NAN tal como se especifica en el IEEE 754. El error E_WARNING del
operador de módulo ha sido eliminado, lanzando ahora 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
Los string que contienen números hexadecimales ya no se consideran numéricos. 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"
Se puede emplear filter_var() para comprobar si un string contiene un numero hexadecimal, y también para convertir un string de dicho tipo en un integer:
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
throw new Exception("¡Número entero inválido!");
}
var_dump($int); // int(65535)
?>
Debido a la incorporación de la nueva sintaxis de escape de puntos de código de Unicode, los string que contienen un literal \u{ seguido de una secuencia inválida causarán un error fatal. Para evitarlo, se debería escapar la barra inicial.
Estas funciones estaban obsoletas en PHP 4.1.0 en favor de call_user_func() y call_user_func_array(). Se podría también considerar el uso de funciones variables y/o el operador ....
Se han eliminado todas las funciones de ereg. Se recomienda PCRE como alternativa.
Se ha eliminado la función obsoleta mcrypt_generic_end() en favor de mcrypt_generic_deinit().
También se han eliminado las funciones obsoletas mcrypt_ecb(),
mcrypt_cbc(), mcrypt_cfb() y
mcrypt_ofb() en favor del
uso de mcrypt_decrypt() con la constante
MCRYPT_MODE_*
apropiada.
Se han eliminado todas las funciones de ext/mysql. Para más detalles sobre elegir una API de MySQL diferente, Véase Elegir una API de MySQL.
Se han eliminado todas las funciones de ext/mssql. Para un listado de alternativas, veáse la Introudcción a MSSQL.
Se han eliminado los alias obsoletos datefmt_set_timezone_id() y IntlDateFormatter::setTimeZoneID() en favor de datefmt_set_timezone() y IntlDateFormatter::setTimeZone(), respectivamente.
Se ha eliminado set_magic_quotes_runtime(), junto con su alias magic_quotes_runtime(). Estaban obsoletos en PHP 5.3.0, y de hecho se quedaron sin funcionalidad con la eliminación de las comillas mágicas en PHP 5.4.0.
Se ha eliminado el alias obsoleto set_socket_blocking() en favor de stream_set_blocking().
dl() ya no se puede utilizar en PHP-FPM. Permanece funcional en CLI y en SAPI embebidas.
Se ha eliminado el soporte para fuentes Type1 de PostScript de la extensión GD, resultado en la eliminación de las siguientes funciones:
Se recomienda utilizar fuentes TrueType y sus asociadas en su lugar.
Las siguientes directivas INI han sido eliminadas, así como sus características asociadas:
xsl.security_prefs
Ha sido eliminada la directiva xsl.security_prefs
.
En su lugar, debería llamarse al método XsltProcessor::setSecurityPrefs()
para controlar las preferencias de seguridad en función de
cada procesador.
El resultado de la sentencia 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 se pueden emplear para nombrar a clases, interfaces o rasgos:
Tampoco deberían utilizarse los siguientes nombres. Aunque no generan un error en PHP 7.0, están reservados para un uso futuro, por lo que deberían considerarse obsoletos.
Se ha eliminado el soporte para usar etiquetas ASP y de script para delimitar código de PHP. Las etiquetas afectadas son:
Etiqueta de apertura | Etiqueta de cierre |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
Ya obsoletas en PHP 5.6, las llamadas estáticas realizadas a un método no estático con un contexto incompatible resultarán ahora en la tenencia del método llamado de una variable $this indefinida y en la emisión de una advertencia de obsolescencia.
<?php
class A {
public function prueba() { var_dump($this); }
}
// Nota: NO extiende a A
class B {
public function llamadaAMétodoNoEstáticoDeA() { A::prueba(); }
}
(new B)->llamadaAMétodoNoEstáticoDeA();
?>
Salida del ejemplo anterior en PHP 5.6:
Deprecated: Non-static method A::prueba() 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::prueba() should not be called statically in /tmp/test.php on line 8 Notice: Undefined variable: this in /tmp/test.php on line 3 NULL
El constructor yield ya no requiere paréntesis, ya que ha pasado a ser un operador asociativo derecho con precedencia entre print y =>. Esto puede resultar en un cambio de comportamiento:
<?php
echo yield -1;
// Anteriormente era interpretado como
echo (yield) - 1;
// Y ahora es intrepretado como
echo yield (-1);
yield $foo or die;
// Anteriormente era interpretado como
yield ($foo or die);
// Y ahora es intrepretado como
(yield $foo) or die;
?>
Los paréntesis se pueden emplear para desambiguar estos casos.
Ya no es posible definir dos o más parámetros de función con el
mismo nombre. Por ejemplo, el siguiente método generará un error
E_COMPILE_ERROR
:
<?php
function foo($a, $b, $sin_usar, $sin_usar) {
//
}
?>
func_get_arg(), func_get_args(), debug_backtrace() y las excepciones de información de rastreo ya no informarán del valor original que fue pasado a un paramétro, en su lugar proporcionarán el valor actual (el cual 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 default en una sentencia
switch. Por ejemplo, la siguiente senetencia switch generará un error
E_COMPILE_ERROR
:
<?php
switch (1) {
default:
break;
default:
break;
}
?>
$HTTP_RAW_POST_DATA ya no está disponible. Debería usarse el flujo php://input en su lugar.
Se ha eliminado el soporte para los comentarios prefijados con # en los ficheros INI. Se debe emplear en su lugar ; (punto y coma). Este cambio se aplica a php.ini, así como a ficheros manejados por parse_ini_file() y parse_ini_string().
Se ha reemplazado la extensión JSON por JSOND ocasionando tres roturas de RC (retocompatibilidad). La primera, un número no puede finalizar con un punto decimal (esto es, 34. debe cambiarse para que sea o 34.0 o 34). La segunda, al utilizar notación científica, el exponente e no debe seguir inmediatamente a un punto decimal (esto es, 3.e3 se debe cambiar para que sea o 3.0e3 o 3e3). Finalmente, una cadena vacía ya no se considera un JSON válido.
Anteriormente, las funciones internas truncaban de forma silenciosa números producidos desde
coacciones de tipo float a integer cuando el float era demasiado grande de representar como un
integer. Ahora, se emitirá un E_WARNING y se devolverá NULL
.
Cualquier función declarada implementada por gestores de sesión personalizados que devuelvan
o FALSE
o -1 serán errores fatales. Si desde estas funciones
se devuelve cualquier valor distinto de un booleano, -1, o
0, fallarán y se emitirá un
E_WARNING.
El algoritmo de ordenación interno ha sido mejorado, lo cual puede resultar en un orden diferente de elementos, que se comparan como iguales, que antes.
Nota:
No dependa del orden de los elementos que se comparan como iguales; podría cambiar en cualquier momento.