[PHP] Notice: Only variables should be passed by reference usando la función end

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

Website |  + posts

Automation & Data Specialist | Web Development | Data Processing & Integration

Deja un comentario