A veces nos encontramos en la situación en la que tenemos que procesar grandes arreglos y tenemos que rompernos la cabeza para no caer en el problema de exceso de memoria. Por eso en este artículo vamos a ver el poder de la sentencia yield de PHP para solucionar problemas como este. 💪
¿Qué es la sentencia Yield de PHP?
En mis años de experiencia utilizando PHP no vi que se utilice mucho la sentencia yield. No sé si será por desconocimiento o que. Pero yield nos permite «hacer un return» sin cortar el proceso y esto lo podemos utilizar en muchas situaciones en donde recorrer un arreglo puede demorar mucho tiempo.
Veámoslo en un ejemplo muy simple. Supongamos que tenemos una función que genera información que luego necesitamos procesar, (imprimir en este caso):
En este caso, estamos generando información, la metemos en un arreglo y luego lo devolvemos para utilizarla.
Sabemos que cada elemento de un arreglo es memoria ocupada en la maquina y esto podría resultar muy costoso. Entonces, ¿no sería mejor procesar cada elemento mientras se va generando y no esperar a qué se termine de cargar el arreglo final?
Entonces, acá es donde entra en juego la sentencia Yield.
Implementación de la sentencia Yield
Esta palabra clave nos permite «devolver» cada elemento iterado. ¿Y por qué lo pongo entre comillas? Porque, si bien el elemento es devuelto, la función no finaliza. Sino que espera a que se vuelva a iterar $data
para devolver el próximo elemento.
Mejor veamos como sería el ejemplo anterior implementando yield.
Como ven, no hace falta guardar cada elemento en un arreglo para luego devolverlo. Si no que, cada vez que el foreach
itere la variable $data
, el sistema devolverá el próximo elemento de información.
¿En qué nos podría ser útil la sentencia yield?
Imaginen que quieren procesar un archivo csv que contiene varios registros de productos. Y necesitas leerlo para generar un informe.
Por ejemplo, queremos saber los productos que no hemos regalado en este mes. Entonces, leemos un archivo que contiene los productos vendidos en este mes y los filtramos por los que tienen precio.
Sin dudas, este proceso puede reventar por exceso de memoria ya que no sabemos cuantos productos pueden venir en el archivo.
La manera más optima y segura que tenemos de hacer esto es utilizando yield de la siguiente forma:
Haciendo pruebas con un archivo bastante grande, esto fueron los resultados:
sin Yield | usando Yield | |
Memoria consumida | 20.43Mb | 0.21Mb |
Tiempo de ejecución | 0.083s | 0.113s |
Como ven, utilizando la palabra clave yield el proceso se demora más pero el consumo de memoria es muy bajo. Esto nos evitaría tener que estar modificando el parámetro memory_limit
de php en tiempo de ejecución o en nuestro php.ini
.
Contras de Yield
Una de las contras, como acabamos de ver, es que el proceso demora más tiempo. Así que deberíamos utilizarlo en los momentos adecuados.
Otro de los puntos negativos de yield es que no podemos volver a recorrer un arreglo que ya hemos recorrido.
En el último ejemplo, no podríamos volver a recorrer la variable $productsNoFree
luego del foreach
. Ya que, los elementos no quedan guardados en memoria.
Una curiosidad: Yield en Laravel
A partir de Laravel 6 se agregaron las Lazy Collection y en su documentación dice que «permiten trabajar con conjuntos de datos muy grandes mientras mantiene bajo el uso de memoria.». ¿Y adivina por qué? Así es! por las sentencia yield.
Conclusión
Te invito a investigar más sobre la sentencia yield ya que es mucho más poderosa que los simples ejemplos que vimos aquí. Espero que te haya gustado este artículo y compártelo si así fue 😃. Nos vemos en la próxima.
Super…..!! Y muchas gracias…..
Muy buen tip y como siempre un detalle de Matias: «este proceso puede reventar» 😂😂😂
Muchas gracias Matias! muy buen detalle!
Excelente Articulo!!
Gracias por compartir tus conocimiento!!
excelente dato no lo conocía gracias.
Amigo buenos días, como haces para medir la memoria y el tiempo de ejecución en PHP, por ejemplo en Js es con console.time aquí como seria ?
Excelete tips!!
Muchas gracias Alejandro!