Resumen sobre los generadores
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
Los generadores proporcionan una manera sencilla de implementar
iteradores
sin el costo ni la complejidad de desarrollar una clase que implemente
la interfaz Iterator.
Un generador ofrece un medio conveniente para proporcionar datos a las bucles foreach
sin
tener que construir un array en memoria de antemano, lo cual podría llevar al programa
a exceder un límite de memoria o requerir un tiempo de procesamiento considerable para generarlos.
En su lugar, se puede utilizar una función generadora,
que es idéntica a una
función normal,
excepto que en lugar de devolver
una sola vez, un generador puede utilizar yield
tantas veces como sea necesario, para
proporcionar los valores a recorrer.
Al igual que con los iteradores, el acceso aleatorio a los datos no es posible.
Un ejemplo sencillo de este mecanismo es la reimplementación
de la función range() en forma de generador.
La función estándar range() debe generar un array
que contenga cada valor y devolverlo, lo cual puede llevar
a arrays de gran tamaño: por ejemplo, la llamada al código
range(0, 1000000) puede consumir significativamente más de
100 MB de memoria.
Como alternativa, se puede implementar un generador
xrange()
, que solo necesitará memoria para la creación de un objeto Iterator, y deberá mantener internamente el estado actual del generador, lo cual resulta en un consumo de memoria inferior a 1 KB.
Ejemplo #1 Implementación de la función range() en forma de generador
<?php
function xrange($start, $limit, $step = 1) {
if ($start <= $limit) {
if ($step <= 0) {
throw new LogicException('El paso debe ser positivo');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('El paso debe ser negativo');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
/*
* Es de notar que las funciones range() y xrange() producen el
* mismo resultado, a continuación.
*/
echo 'Números impares de un solo dígito desde range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Números impares de un solo dígito desde xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
El ejemplo anterior mostrará :
Números impares de un solo dígito desde range(): 1 3 5 7 9
Números impares de un solo dígito desde xrange(): 1 3 5 7 9
Cuando se llama a una función generadora,
se devuelve un objeto de la clase interna Generator. Este objeto implementa la interfaz Iterator
de la misma manera que lo haría un objeto iterador que solo avanza, y proporciona los métodos que pueden ser llamados para manipular el estado
del generador, incluyendo el envío de valores y sus retornos.