Muitos erros fatais e recuperáveis foram convertidos para exceções no PHP 7. Estas exceções herdam a classe Error, que implementa a interface Throwable (a interface base da qual todas as exceções herdam).
Isso significa que manipuladores de erros podem não ser ativados porque exceções estão sendo disparadas em seu lugar (causando novos erros fatais por exceções Error não capturadas)
Uma descrição completa de como tratar erros no PHP 7 pode ser encontrada na página de erros do PHP 7. Este guia de migração irá enumerar apenas as mudanças compatíveis com versões anteriores.
Códigos que implementam um manipulador de exceção registrado com set_exception_handler() usando a declaração de tipo Exception causará um erro fatal quando um objeto Error for lançado.
Se o manipulador precisa trabalhar com o PHP 5 e 7, você deve remover a declaração de tipo do manipulador, enquanto que o código a migrar para funcionar exclusivamente no PHP 7, pode simplesmente trocar a declaração de tipo Exception por Throwable.
<?php
// Código da era PHP 5 que não irá funcionar.
function handler(Exception $e) { ... }
set_exception_handler('handler');
// Compatível com PHP 5 e 7.
function handler($e) { ... }
// Somente PHP 7.
function handler(Throwable $e) { ... }
?>
Anteriormente, algumas classes internas retornavam null
ou um objeto inútil
quando o construtor falhava. Todas as classes internas agora lançam
Exception neste caso, da mesma forma que
classes de usuário já faziam.
Erros de Parser agora lançam um objeto ParseError. Manipular
erros da função eval() devem incluir um bloco catch
que possa manipular este erro.
Todas as notificações E_STRICT
foram reclassificadas para
outros níveis. A constante E_STRICT
foi mantida, então chamar
error_reporting(E_ALL|E_STRICT)
não causará um erro.
Situação | Novo nível/Comportamento |
---|---|
Utilizar um recurso como índice | E_NOTICE |
Métodos estáticos abstratos | Notificação removida, não dispara erro |
"Redefinindo" um construtor | Notificação removida, não dispara erro |
Assinatura incompatível durante a herança | E_WARNING |
Mesmas propriedades(compatíveis) em duas traits utilizadas | Notificação removida, não dispara erro |
Acessando propriedades estáticas de forma não estática | E_NOTICE |
Somente variáveis devem ser ser atribuídas por referência | E_NOTICE |
Somente variáveis devem ser passadas por referência | E_NOTICE |
Chamando métodos não estáticos de forma estática | E_DEPRECATED |
O PHP 7 utiliza uma sintaxe abstrata de árvore para analisar os arquivos fonte. Isso permitiu diversas melhorias para a linguagem que eram impossíveis devido a limitações no analisador utilizado em versões anteriores do PHP, porém resultou na remoção de alguns casos especiais por razões de consistência, que resulta em quebras de compatibilidades com versões anteriores. Esses casos são detalhados nesta seção.
Acessar indiretamente variáveis, propriedades, e métodos, agora serão avaliados estritamente da esquerda para a direita, o oposto dos casos especiais em versões anteriores. A tabela a seguir mostra como a ordem de avaliação mudou.
Expressão | Interpretação no PHP 5 | Interpretação no 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']()
|
Códigos que usam a ordem de avaliação da direita para esquerda devem ser reescritos para o uso explícito da ordem de avaliação com chaves (veja a coluna do meio). Isso fará com que o código seja compatível com versões posteriores ao PHP 7.x e compatível com o PHP 5.x.
Isso também afeta a palavra chave global
. A sintaxe com chaves pode ser
usada para emular o comportamento anterior se necessário:
<?php
function f() {
// Válido apenas no PHP 5.
global $$foo->bar;
// Válido no PHP 5 e 7.
global ${$foo->bar};
}
?>
A função list() agora irá atribuir valores as variáveis na
ordem em que foram definidas, em vez de ordem reversa. De modo geral, isso só
afeta casos onde a função list() é utilizada em
conjunção com o operador de array []
, como mostrado a seguir:
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
Saída do exemplo acima no PHP 5:
array(3) { [0]=> int(3) [1]=> int(2) [2]=> int(1) }
Saída do exemplo acima no PHP 7:
array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
De modo geral, é recomendo não confiar na ordem em que as atribuições com que a função list() ocorrem, como sua implementação detalha, isso pode mudar novamente no futuro.
Chamadas a função list() não podem mais ser vazias. O que é visto a seguir não é mais permitido:
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
A função list() não podem mais desempacotar variáveis do tipo string. Em vez disso, a função str_split() deve ser usada.
A ordem dos elementos no array foi modificada quando estes elementos foram automaticamente criados por referenciação em uma atribuição por referência. Por exemplo:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
Saída do exemplo acima no PHP 5:
array(2) { ["b"]=> &int(1) ["a"]=> &int(1) }
Saída do exemplo acima no PHP 7:
array(2) { ["a"]=> &int(1) ["b"]=> &int(1) }
No PHP 5, usar parênteses redundantes em torno de parâmetros de uma função podem disparar avisos de quebra de padrões quando os parâmetros da função fossem passados por referência. Agora, o aviso sempre será emitido.
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Generates a warning in PHP 7.
squareArray((getArray()));
?>
O exemplo acima produzirá:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
Pequenas mudanças foram feitas no modo como a estrutura de controle foreach se comporta, principalmente na manipulação do ponteiro interno do array e modificações no array sendo iterado.
Antes do PHP 7, o ponteiro interno do array era modificado enquanto o array era iterado usando o foreach. Este não é mais o caso, como mostrado nos exemplos a seguir:
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
Saída do exemplo acima no PHP 5:
int(1) int(2) bool(false)
Saída do exemplo acima no PHP 7:
int(0) int(0) int(0)
Quando usado no modo padrão, por valor, o foreach vai operar em uma cópia do array sendo iterado, ao invés do próprio array. Isso significa que mudanças feitas durante a iteração do array, não afetarão os valores iterados.
Quanto iterado por referencia, o foreach fará um melhor trabalho de controlar as alterações feitas ao array durante a iteração. Por exemplo, inclusões ao array enquanto iterado, agora resultam na inclusão de valores enquanto itera, como a seguir:
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
Saída do exemplo acima no PHP 5:
int(0)
Saída do exemplo acima no PHP 7:
int(0) int(1)
Iterar objetos não Traversable agora têm o mesmo comportamento que iterar arrays por referência. Isso resulta na melhora do comportamento quando houver modificações no array durante a iteração também aplicado quando propriedades são adicionadas ou removidas do objeto.
Antes, octais literais que continham números inválidos, eram silenciosamente
truncados (0128
se tornaria 012
).
Agora, um octal literal inválido causará um erro de parse.
Deslocamento de bits por números negativos agora lançarão uma exceção ArithmeticError:
<?php
var_dump(1 >> -1);
?>
Saída do exemplo acima no PHP 5:
int(0)
Saída do exemplo acima no 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
Deslocamentos de bits (em ambas direções), além do tamanho de bits de um int sempre resultará em 0. Antes, o comportamento do deslocamento dependia da arquitetura.
Antes, quando 0 era usado como divisor tanto para a operador de divisão (/) quanto
para o módulo, um E_WARNING era emitido e
false
era retornado. Agora, o operador de divisão
retornará um float +INF, -INF ou NAN, conforme a especificação IEEE 754. O E_WARNING do operador módulo
foi removido e irá lançar uma exceção DivisionByZeroError.
<?php
var_dump(3/0);
var_dump(0/0);
var_dump(0%0);
?>
Saída do exemplo acima no 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)
Saída do exemplo acima no 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
Strings contendo números hexadecimais não são mais consideradas numéricas. Por exemplo:
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
Saída do exemplo acima no PHP 5:
bool(true) bool(true) int(15) string(2) "oo"
Saída do exemplo acima no 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() pode ser usado se uma string contém um número hexadecimal, e também para converter uma string deste tipo para um int:
<?php
$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
throw new Exception("Inteiro Inválido!");
}
var_dump($int); // int(65535)
?>
\u{
pode causar erros
Por conta da adição da nova
sintaxe de escape de códigos em Unicode,
strings contendo um \u{
literal seguido de uma sequência
inválida causará um erro fatal. Para evitar isso,
você deve escapar a barra invertida.
Estas funções foram descontinuadas no PHP 4.1.0 em favor de
call_user_func() e
call_user_func_array(). Você também pode considerar
o uso de
funções variáveis
e/ou o operador
...
.
Todas as funções ereg
foram removidas.
PCRE é uma alternativa recomendada.
A função descontinuada mcrypt_generic_end() foi removida em favor de mcrypt_generic_deinit().
Além disso, as funções descontinuadas mcrypt_ecb(),
mcrypt_cbc(), mcrypt_cfb() e
mcrypt_ofb() foram removidas em favor do
uso da função mcrypt_decrypt() com a constante
MCRYPT_MODE_*
apropriada.
Todas as funções ext/mysql foram removidas. Para mais detalhes sobre a escolha de uma API MySQL diferente, veja a seção Escolhendo uma API MySQL.
Todas as funções ext/mssql
foram removidas.
Os sinônimos descontinuados datefmt_set_timezone_id() e IntlDateFormatter::setTimeZoneID() foram removidos em favor de datefmt_set_timezone() e IntlDateFormatter::setTimeZone(), respectivamente.
set_magic_quotes_runtime(), juntamente com seu sinônimo magic_quotes_runtime(), foram removidos. Eles foram descontinuados no PHP 5.3.0 e se tornaram efetivamente não funcionais com a remoção das magic quotes no PHP 5.4.0.
O sinônimo descontinuado set_socket_blocking() foi removido em favor de stream_set_blocking().
dl() não pode mais ser utilizado no PHP-FPM. Ela permanece funcional na interface CLI e SAPIs embarcadas.
O suporte a fontes PostScript Type1 foi removido da extensão GD, resultando na remoção das seguintes funções:
O uso de fontes TruType e suas funções associadas é recomendado.
As diretivas INI a seguir foram removidas, assim como os como seus recursos associados:
always_populate_raw_post_data
asp_tags
xsl.security_prefs
A diretiva xsl.security_prefs
foi removida.
Em substituição, o método XsltProcessor::setSecurityPrefs()
deve ser chamado para controlar as preferências de segurança
por processo base.
O resultado da declaração new
não pode mais ser atribuído a uma variável
por referência:
<?php
class C {}
$c =& new C;
?>
Saída do exemplo acima no PHP 5:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
Saída do exemplo acima no PHP 7:
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
Os nomes a seguir não podem ser utilizados como nome de classes, interfaces ou traits:
Além disso, os seguintes nomes não devem ser usados. Embora eles não geram um erro no PHP 7.0, eles são reservados para uso futuro e devem ser considerados descontinuados.
O suporte ao uso das tags ASP e script para delimitar o código PHP foi removido. As tags afetadas são:
Tag de abertura | Tag de fechamento |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
Anteriormente descontinuadas no PHP 5.6,
chamadas estáticas feitas a métodos não-estáticos com um contexto incompatível agora
resultarão no método chamado tendo uma variável
$this
indefinida e um aviso de descontinuação será emitido.
<?php
class A {
public function test() { var_dump($this); }
}
// Nota: NÃO extende A
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
Saída do exemplo acima no 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) { }
Saída do exemplo acima no 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
O construtor yield não requer mais o uso de parênteses e foi alterado
para um operador associativo à direita com precedência entre
print
e =>
. Isso pode resultar em um
comportamento alterado:
<?php
echo yield -1;
// Era interpretado como
echo (yield) - 1;
// E agora é interpretado como
echo yield (-1);
yield $foo or die;
// Era interpretado como
yield ($foo or die);
// E agora é interpretado como
(yield $foo) or die;
?>
Parênteses podem ser utilizados para remover a ambiguidade nestes casos.
Não é mais possível definir dois ou mais parâmetros em uma função com o
mesmo nome. Por exemplo, a função a seguir vai disparar um
E_COMPILE_ERROR
:
<?php
function foo($a, $b, $unused, $unused) {
//
}
?>
func_get_arg(), func_get_args(), debug_backtrace() e backtraces de exceção não informam mais o valor original que foi passado para um parâmetro, mas ao invés disso, irão informar o valor atual (que pode ter sido modificado).
<?php
function foo($x) {
$x++;
var_dump(func_get_arg(0));
}
foo(1);?>
Saída do exemplo acima no PHP 5:
1
Saída do exemplo acima no PHP 7:
2
Não é mais possível definir dois ou mais blocos default em uma declaração
switch. Por exemplo, a declaração switch a seguir irá disparar um
E_COMPILE_ERROR
:
<?php
switch (1) {
default:
break;
default:
break;
}
?>
A variável $HTTP_RAW_POST_DATA não está mais disponível. Ao invés
disso o stream php://input
deve ser utilizado.
#
nos arquivos INI foram removidos
O suporte a comentários prefixados com #
nos arquivos INI foi
removido. Em vez disso, o ;
(ponto-e-vírgula) deve ser usado. Esta mudança
aplica-se ao php.ini, assim como aos arquivos manipulados pelas funções
parse_ini_file() e parse_ini_string().
A extensão JSON foi substituída por JSOND, causando três quebras menores de compatibilidade com versões
anteriores. Em primeiro lugar, um número não pode ser terminado em um ponto decimal (isto é,
34.
deve ser modificado para 34.0
ou
34
). Em segundo lugar, ao usar notação científica, o
expoente e
não deve seguir imediatamente o ponto decimal
(isto é, 3.e3
deve ser modificado para
3.0e3
ou 3e3
).
Finalmente, uma string vazia não é mais considerada JSON válido.
Antes, funções internas silenciosamente truncavam números produzidos por
coerções de pontos flutuantes para inteiros quando o ponto flutuante era grande demais para ser representado como um
inteiro. Agora um E_WARNING será emitido e null
será retornado.
Quaisquer funções de predicado implementadas por manipuladores de sessões customizadas que retornem
false
ou -1
resultarão em erros fatais. Se qualquer valor retornado
destas funções não é um booleano, -1
ou
0
, então ela irá falhar e um E_WARNING será
emitido.
O algoritmo interno de ordenação foi melhorado, o que pode resultar em diferentes ordenações de elementos, que são comparados como iguais, do que antes.
Nota:
Não confie na ordem de elementos que são comparados como iguais; ela pode mudar a qualquer momento.
As declarações break
e continue
fora de um
laço ou de uma estrutura de controle switch
, agora são detectados em
tempo de compilação em vez de tempo de execução como antes, e dispara um erro
E_COMPILE_ERROR
.
As instruções break
e continue
não mais
permitem que seus argumentos sejam uma constante, e emitem um
E_COMPILE_ERROR
.
A extensão Mhash foi completamente integrada na extensão Hash. Portanto, não é mais possível detectar o suporte à extensão Mhash com extension_loaded(); em vez disso use function_exists(). Além disso, Mhash não é mais informada por get_loaded_extensions() e recursos relacionados.
A diretiva declare(ticks) não vaza mais para diferentes unidades de compilação.