Seguro que muchos de vosotros os habéis topado con un aviso como el del título:
Notice: Only variables should be passed by reference.
Uno de los tantos avisos que podemos encontrarnos mientras trabajamos con PHP.
Es un notice, no pasa nada.
Sí, sí pasa. Y más si trabajamos en producción. Este tipo de avisos han de subsanarse y no parchearse con un error_reporting(0); y que sea lo que Dios quiera.
Curiosamente, estaba trasteando con un tutorial sobre un uploader múltiple de imágenes y me topé con ese pequeño código que tanto me irritaba a los ojos durante el tutorial:
$ext = end((explode(".", $filename)));
Esto puede funcionar, pero nos encontraremos con el famoso Notice: Only variables should be passed by reference.
Y todo por no leerse bien la documentación de PHP, que no es precisamente escasa.
La función end() hace lo siguiente:
end — Set the internal pointer of an array to its last element
Y si consultamos su definición, encontramos:
end (array &$array) : mixed
Ese & es la clave.
El array se pasa por referencia porque end() modifica su puntero interno. Por este motivo, debemos pasarle una variable que pueda ser pasada por referencia, y no el resultado temporal de una función.
La propia documentación de PHP lo explica:
The array. This array is passed by reference because it is modified by the function. This means you must pass it a real variable and not a function returning an array because only actual variables may be passed by reference.
Dicho de otra forma: explode() nos devuelve un array, pero ese array es un resultado temporal. No podemos pasárselo directamente a end() esperando que pueda ser modificado por referencia.
¿Y cómo solventamos dicho error?
Pues tan fácil como asignar el resultado de explode() a una variable y después pasar dicha variable a end():
$tmp = explode(".", $filename);
$ext = end($tmp); // Le pasamos una variable, no el resultado de una función.
Y con esto ya tenemos el pequeño problema arreglado.
⚠️ Nota para PHP 8.0 y versiones posteriores
Si estás utilizando PHP 8.0 o una versión posterior, ten en cuenta que el comportamiento de este tipo de errores cambió.
En versiones anteriores a PHP 8.0, pasar directamente el resultado de una función como explode() a end() podía producir el conocido:
Notice: Only variables should be passed by reference
A partir de PHP 8.0, este tipo de situaciones puede provocar directamente una excepción Error con un mensaje como:
Argument cannot be passed by reference
Por tanto, aunque el título de este artículo haga referencia al Notice original, el problema de fondo sigue siendo el mismo: end() necesita recibir un argumento que pueda pasarse por referencia.
La solución sigue siendo sencilla:
$tmp = explode(".", $filename);
$ext = end($tmp);
Y, si simplemente queremos obtener la extensión de un archivo, en PHP moderno es todavía mejor utilizar directamente:
$ext = pathinfo($filename, PATHINFO_EXTENSION);
Consejo: no te acostumbres a silenciar estos avisos o errores. Si PHP te está diciendo que algo no puede pasarse por referencia, merece la pena entender el motivo y corregirlo.
Pero hoy tenemos una opción todavía mejor.
Si lo que queremos realmente es obtener la extensión de un archivo, no necesitamos utilizar explode() y end().
PHP ya nos proporciona pathinfo() precisamente para este cometido:
$ext = pathinfo($filename, PATHINFO_EXTENSION);
Mucho más claro y, sobre todo, expresa directamente nuestra intención: quiero obtener la extensión de este archivo.
Por ejemplo:
$filename = 'imagen.jpg'; $ext = pathinfo($filename, PATHINFO_EXTENSION); echo $ext; // jpg
Por tanto, si nos encontramos hoy con código como:
$ext = end(explode(".", $filename));
podemos solucionarlo manteniendo el enfoque original:
$tmp = explode(".", $filename);
$ext = end($tmp);
Pero si lo que queremos es obtener la extensión de un archivo, la opción recomendada y mucho más semántica sería:
$ext = pathinfo($filename, PATHINFO_EXTENSION);
Así que sí: aquel pequeño Notice tenía una explicación bastante interesante detrás.
No era simplemente “PHP dando por culo”.
Era una consecuencia de cómo funcionan las referencias en PHP y de que end() necesita recibir una variable que pueda modificar por referencia.
Y, como siempre, antes de silenciar el error con error_reporting(0), quizá sea mejor averiguar primero por qué coño aparece.
Saludos!.
Visitas: 3233
Automation & Data Specialist | Web Development | Data Processing & Integration
