Mensaje de error "Normas estrictas: solo las variables deben pasarse por referencia"

81
$el = array_shift($instance->find(..))

El código anterior informa de alguna manera la advertencia de estándares estrictos, pero esto no:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Entonces, ¿cuándo informará la advertencia de todos modos?

user198729
fuente
1
¿Qué devuelve $ instancia-> encontrar (..)?
Silver Light
2
Aquí está la solución: stackoverflow.com/questions/9848295/…
ajaristi
Creo que los ejemplos (o lógica) podrían ser la ronda de manera incorrecta en la cuestión, ya que el segundo ejemplo ( get_arr()función) no producir el aviso estricta estándares (probado PHP 5.2 y PHP 5.5).
MrWhite

Respuestas:

93

Considere el siguiente código:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

Esto generará la siguiente salida:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

¿La razón? El test::get_arr()método no es una variable y en modo estricto esto generará una advertencia. Este comportamiento es extremadamente no intuitivo ya que el get_arr()método devuelve un valor de matriz.

Para evitar este error en modo estricto, cambie la firma del método para que no use una referencia:

function test_arr($a) {
    var_dump($a);
}

Como no puede cambiar la firma de array_shift, también puede usar una variable intermedia:

$inter = get_arr();
$el = array_shift($inter);
leepowers
fuente
7
@ user198729: Estaba buscando una explicación o solución también, y descubrí que puede usar current () para el primer elemento. Por desgracia, end () no funciona para el último puesto que "avanza el puntero interno al último elemento". current (array_reverse (somefunction ())) funciona (sí, es una tontería)
MSpreij
1
El uso currentsupone que el puntero de la matriz está en el primer elemento. Puede ser una suposición válida en la mayoría de los casos, pero hay que tener cuidado.
cmbuckley
1
@leepowers Por supuesto, entonces habría el mismo problema array_shift()que espera una referencia para modificar :-)
cmbuckley
1
@ user198729 Puede evitar el $intermediatevalor utilizando un par adicional de paréntesis. $el = array_shift( ( get_arr() ) );. Ver stackoverflow.com/questions/9848295/…
Chloe
1
@Chloe ¡Esta es la solución más brillante que he visto para mantener el código simple! ¡Gracias!
hargobind
7

$instance->find() devuelve una referencia a una variable.

Obtiene el informe cuando intenta utilizar esta referencia como argumento para una función, sin almacenarlo primero en una variable.

Esto ayuda a prevenir pérdidas de memoria y probablemente se convertirá en un error en las próximas versiones de PHP.

Su segundo bloque de código arrojaría un error si escribiera como (tenga &en cuenta en la firma de la función):

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Entonces, una solución rápida (y no tan agradable) sería:

$el = array_shift($tmp = $instance->find(..));

Básicamente, primero haces una asignación a una variable temporal y envías la variable como argumento.

Sagi
fuente
Debería funcionar ahora (lo comprobó). Para devolver la referencia, debe declararla en la firma del método, no en la declaración de devolución (culpa mía).
Sagi
No, no puedo cambiar la firma. La variable intermedia de @ pygorex1 puede resolver esto, pero parece redundante, ¿no?
user198729
Sé que no puedes cambiar la firma, solo expliqué cómo sucede. Usted tiene que utilizar (= intermedio) variable temporal, pero puede hacerlo en la misma línea. Mira mi segundo fragmento de código.
Sagi
4
Probé
3
En efecto. Una asignación devuelve el valor asignado . array_shift($tmp = $instance->find(..))asigna el valor de $instance->find(..)a $tmpy luego pasa el valor de la asignación a array_shift()- que no es lo mismo que pasa a $tmpsí mismo, así que no es mejor que la situación original sin la asignación es.
phils
6

La causa del error es el uso de la función de estructuras de datos de programación interna de PHP, array_shift () [php.net/end].

La función toma una matriz como parámetro. Aunque se indica un ampersand en el prototipo de array_shift()en el manual ", no hay ninguna documentación de advertencia a continuación en la definición extendida de esa función, ni hay ninguna explicación aparente de que el parámetro se pasa de hecho por referencia.

Quizás esto sea / entendido /. Sin embargo, no entendí, por lo que fue difícil para mí detectar la causa del error.

Reproducir código:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
Biju B Adoor
fuente
3

Este código:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

Necesita cambiarse a:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
user6031348
fuente
0

Bueno, en casos obvios como ese, siempre puedes decirle a PHP que suprima mensajes usando "@" delante de la función.

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

Puede que no sea una de las mejores prácticas de programación eliminar todos los errores de esta manera, pero en ciertos casos (como este) resulta útil y aceptable.

Como resultado, estoy seguro de que su amigo 'administrador del sistema' estará satisfecho con un sistema menos contaminado error.log.

Julio Marchi
fuente
No sé quién votó en contra de esta respuesta, pero la solución presentada SÍ funciona y ES una técnica estándar de PHP. Realmente decepcionante ... La próxima vez puede que ya no responda una pregunta ... :(
Julio Marchi
5
Asumiría que fue porque suprimir el mensaje de error no soluciona el problema con el código. ¿Qué hará cuando este tipo de error cambie de E_STRICT a E_ERROR en una versión futura de PHP y su código ahora no se ejecute y tampoco produzca ningún error / salida?
Lucas
@TinoDidriksen, entiendo y estoy de acuerdo con las razones para desaconsejar algunos "malos hábitos", especialmente para las nuevas generaciones. Sin embargo, un recurso existe para ser utilizado cuando (y si) es seguro de usar y aplicable al contexto propuesto. Si se suprimiera el supresor de errores "@", se habría eliminado del propio idioma. Igual que "eval" (puede ser maligno, pero tiene sus propósitos). No estoy en contra del uso de algunos recursos, sino de la generalización de un consejo. Específicamente para el caso propuesto, no sería perjudicial usarlo, ni siquiera con fines de depuración.
Julio Marchi