PHP 5.4 Passagem por referência de tempo de chamada - Correção fácil disponível?

219

Existe alguma maneira de corrigir esse problema com facilidade ou eu realmente preciso reescrever todo o código legado?

Erro fatal do PHP: A passagem por referência do tempo de chamada foi removida em ... on line 30

Isso acontece em todos os lugares, pois as variáveis ​​são passadas para funções como referências em todo o código.

bardiir
fonte

Respostas:

344

Você deve denotar a chamada por referência na definição da função, não na chamada real. Desde que o PHP começou a mostrar os erros de descontinuação na versão 5.3, eu diria que seria uma boa idéia reescrever o código.

A partir da documentação :

Não há sinal de referência em uma chamada de função - apenas nas definições de função. Somente as definições de função são suficientes para transmitir corretamente o argumento por referência. A partir do PHP 5.3.0, você receberá um aviso dizendo que "chamada em tempo de passagem por referência" é obsoleto quando você usa &no foo(&$a);.

Por exemplo, em vez de usar:

// Wrong way!
myFunc(&$arg);               # Deprecated pass-by-reference argument
function myFunc($arg) { }

Usar:

// Right way!
myFunc($var);                # pass-by-value argument
function myFunc(&$arg) { }
Tim Cooper
fonte
9
Deprecation é desde o PHP 5.0.0, de volta esse tempo dando E_COMPILE_WARNINGerro nível, para referência: php.net/manual/en/...
hakre
5
Eu tive esse erro, mas precisava remover o & insted de adicionar à variável.
267 Diana Diana
2
Eu usei isso no código antigo para um objeto chamado event (& $ event) e tive que remover o e comercial para que a mensagem de erro desaparecesse.
Natalia
1
em todos os meus anos como desenvolvedor, eu nunca precisei usar o & php. jamais. era exatamente isso que eu estava procurando. grande
Juan Vilar
8
para as pessoas nos comentários, observe que a remoção de & pode resultar em resultados inesperados, pois quaisquer alterações na variável não serão mais compartilhadas, mas serão visíveis apenas no escopo local das funções. Então, se você não sabe o que o código faz, eu recomendo corrigi-lo como descrito acima em vez de apenas removendo o & caráter
xorinzor
8

Para quem, como eu, lê isso porque precisa atualizar um projeto herdado gigante para a versão 5.6: como as respostas aqui apontam, não há solução rápida: você realmente precisa encontrar cada ocorrência do problema manualmente e corrigi-lo .

A maneira mais conveniente que encontrei para encontrar todas as linhas problemáticas em um projeto (além de usar um analisador de código estático completo, que é muito preciso, mas não conheço nenhum que o leve à posição correta no editor imediatamente) estava usando o Visual Studio Code, que possui um bom linter PHP embutido, e seu recurso de pesquisa que permite pesquisar pelo Regex. (Obviamente, você pode usar qualquer editor de IDE / código para isso que faça buscas em PHP e Regex em PHP).

Usando este regex:

^(?!.*function).*(\&\$)

é possível pesquisar em todo o projeto a ocorrência de &$apenas linhas que não são uma definição de função.

Isso ainda gera muitos falsos positivos, mas facilita o trabalho.

O navegador de resultados de pesquisa do VSCode facilita a navegação e a localização das linhas incorretas: basta clicar em cada resultado e procurar as que o linter sublinha em vermelho. Aqueles que você precisa consertar.

Pekka
fonte
1
Era isso que eu estava procurando!
Sonny
4
Regex mais preciso que estou usando para este fim:(?<!function)[:> ][a-zA-Z0-9_]+(?<!foreach|array)\s?\([^()]*&\$
Mojo
basta usar phpcs, irá desenterrar todos os arquivos que possuem isso para você.
Thomas Cheng
6

PHP e referências não são intuitivas. Se usadas adequadamente, as referências nos lugares certos podem fornecer grandes melhorias de desempenho ou evitar soluções muito feias e códigos incomuns.

A seguir irá produzir um erro:

 function f(&$v){$v = true;}
 f(&$v);

 function f($v){$v = true;}
 f(&$v);

Nada disso precisa falhar, pois pode seguir as regras abaixo, mas sem dúvida foi removido ou desativado para evitar muita confusão herdada.

Se eles funcionaram, ambos envolvem uma conversão redundante em referência e o segundo também envolve uma conversão redundante em uma variável contida no escopo.

O segundo costumava ser possível, permitindo que uma referência fosse passada para um código que não se destinava a trabalhar com referências. Isso é extremamente feio para manutenção.

Isso não fará nada:

 function f($v){$v = true;}
 $r = &$v;
 f($r);

Mais especificamente, transforma a referência novamente em uma variável normal, pois você não solicitou uma referência.

Isso funcionará:

 function f(&$v){$v = true;}
 f($v);

Isso mostra que você está passando uma não referência, mas quer uma referência, então a transforma em uma referência.

O que isso significa é que você não pode passar uma referência a uma função em que uma referência não é solicitada explicitamente, tornando-a uma das poucas áreas em que o PHP é rigoroso quanto à passagem de tipos ou, nesse caso, mais do tipo meta.

Se você precisar de um comportamento mais dinâmico, isso funcionará:

 function f(&$v){$v = true;}
 $v = array(false,false,false);
 $r = &$v[1];
 f($r);

Aqui ele vê que você quer uma referência e já tem uma referência, então deixa em paz. Também pode encadear a referência, mas duvido disso.

jgmjgm
fonte