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);
?>Resultado del ejemplo anterior en PHP 5:
array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}
Resultado 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);
?>Resultado del ejemplo anterior en PHP 5:
array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}
Resultado 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 ejemplo anterior mostrará:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
foreach
  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.
 
foreach ya no modifica el puntero interno del array
   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));
}
?>Resultado del ejemplo anterior en PHP 5:
int(1) int(2) bool(false)
Resultado del ejemplo anterior en PHP 7:
int(0) int(0) int(0)
foreach por valor trabaja sobre una copia del array
   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.
  
foreach por referencia ha sido mejorado
   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;
}
?>Resultado del ejemplo anterior en PHP 5:
int(0)
Resultado 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);
?>Resultado del ejemplo anterior en PHP 5:
int(0)
Resultado 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 entero 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);
?>Resultado 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)
Resultado 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"));
?>Resultado del ejemplo anterior en PHP 5:
bool(true) bool(true) int(15) string(2) "oo"
Resultado 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 entero:
<?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;
?>Resultado del ejemplo anterior en PHP 5:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
Resultado 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();
?>Resultado 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) {
}
Resultado 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
yield es ahora un operador asociativo derecho
   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);?>Resultado del ejemplo anterior en PHP 5:
1
Resultado 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.
