PHP 5.4 Referencia de tiempo de llamada - ¿Solución fácil disponible?

219

¿Hay alguna forma de solucionar fácilmente este problema o realmente necesito reescribir todo el código heredado?

Error fatal de PHP: se ha eliminado la referencia de tiempo de llamada en ... en la línea 30

Esto sucede en todas partes cuando las variables se pasan a funciones como referencias en todo el código.

bardiir
fuente

Respuestas:

344

Debería denotar la llamada por referencia en la definición de la función, no la llamada real. Desde que PHP comenzó a mostrar los errores de desaprobación en la versión 5.3, diría que sería una buena idea reescribir el código.

De la documentación :

No hay ningún signo de referencia en una llamada de función, solo en las definiciones de función. Las definiciones de funciones solas son suficientes para pasar correctamente el argumento por referencia. A partir de PHP 5.3.0, obtendrá una advertencia diciendo que "llamadas en tiempo pase por referencia" es obsoleto cuando se utiliza &en foo(&$a);.

Por ejemplo, en lugar de usar:

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

Utilizar:

// Right way!
myFunc($var);                # pass-by-value argument
function myFunc(&$arg) { }
Tim Cooper
fuente
99
La desaprobación es desde PHP 5.0.0, en ese momento dando E_COMPILE_WARNINGerror de nivel, para referencia: php.net/manual/en/…
hakre
55
Tuve este error pero necesitaba eliminar el & insted de agregar a la variable.
Diana
2
Tenía esto usado en el código anterior para un objeto llamado evento (& $ evento), y tuve que eliminar el signo y para que desapareciera el mensaje de error.
Natalia
1
En todos mis años como desarrollador, nunca he necesitado usar & en PHP. nunca jamás. Esto era exactamente lo que estaba buscando. genial
Juan Vilar
8
para las personas en los comentarios, tenga en cuenta que eliminar el & puede dar como resultado resultados inesperados ya que cualquier cambio en la variable ya no se compartirá, sino que solo será visible para el alcance local de las funciones. Entonces, a menos que sepa lo que hace el código, le recomiendo que lo
repare
8

Para cualquiera que, como yo, lea esto porque necesita actualizar un proyecto heredado gigante a 5.6: como las respuestas aquí señalan, no hay una solución rápida: realmente necesita encontrar cada ocurrencia del problema manualmente y solucionarlo .

La forma más conveniente que encontré para encontrar todas las líneas problemáticas en un proyecto (salvo el uso de un analizador de código estático completo, que es muy preciso, pero no sé nada que lo lleve a la posición correcta en el editor de inmediato) estaba usando Visual Studio Code, que tiene una bonita interfaz PHP integrada, y su función de búsqueda que permite buscar por Regex. (Por supuesto, puede usar cualquier editor IDE / Code para esto que haga búsquedas de PHP linge y Regex).

Usando esta expresión regular:

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

es posible buscar en todo el proyecto la aparición de &$ solo en líneas que no son una definición de función.

Esto todavía genera muchos falsos positivos, pero facilita el trabajo.

El navegador de resultados de búsqueda de VSCode hace que caminar y encontrar las líneas ofensivas sea muy fácil: simplemente haga clic en cada resultado y busque los que la linter subraya en rojo. Los que necesitas arreglar.

Pekka
fuente
1
¡Esto es lo que estaba buscando!
Sonny
44
Regex más precisa que estoy usando para este propósito:(?<!function)[:> ][a-zA-Z0-9_]+(?<!foreach|array)\s?\([^()]*&\$
Mojo
solo use phpcs, desenterrará cada archivo que tenga esto para usted.
Thomas Cheng
6

PHP y las referencias son algo poco intuitivas. Si se usan adecuadamente, las referencias en los lugares correctos pueden proporcionar grandes mejoras de rendimiento o evitar soluciones muy feas y códigos inusuales.

Lo siguiente producirá un error:

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

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

Ninguno de estos tiene que fallar, ya que podrían seguir las reglas a continuación, pero sin duda se han eliminado o deshabilitado para evitar mucha confusión heredada.

Si funcionaron, ambos implican una conversión redundante a referencia y el segundo también implica una conversión redundante a una variable contenida en el ámbito.

El segundo solía ser posible permitiendo que se pasara una referencia al código que no estaba destinado a funcionar con referencias. Esto es extremadamente feo para la mantenibilidad.

Esto no hará nada:

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

Más específicamente, convierte la referencia nuevamente en una variable normal, ya que no ha solicitado una referencia.

Esto funcionará:

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

Esto ve que está pasando una no referencia pero desea una referencia, por lo que la convierte en una referencia.

Lo que esto significa es que no puede pasar una referencia a una función en la que no se solicita explícitamente una referencia para convertirla en una de las pocas áreas donde PHP es estricto al pasar tipos o, en este caso, más de un metatipo.

Si necesita un comportamiento más dinámico, esto funcionará:

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

Aquí ve que desea una referencia y ya tiene una referencia, así que la deja sola. También puede encadenar la referencia, pero lo dudo.

jgmjgm
fuente