Información general de los generadores
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
Los generadores proporcionan un modo fácil de implementar
iteradores simples sin la
sobrecarga o complejidad de implementar una clase que implemente la
interfaz Iterator.
Un generador permite escribir código que utilice foreach para iterar sobre un
conjunto de datos sin que sea necesario cargar el array en memoria, lo que puede ocasionar
que se exceda el límite de memoria, o requiera una cantidad considerable de
tiempo de procesado para generarse. En su lugar, se puede escribir una función generadora,
que es igual que una
función normal, con la salvedad de que en vez
de
hacer un solo return, un
generador puede invocar yield tantas veces como necesite para proporcionar
valores por los que iterar.
Un ejemplo simple de esto es reimplementar la función range()
como un generador. La función estándar range()
tiene que generar un array con cada uno de los valores y devolverlo, lo que puede
resultar en arrays grandes: por ejemplo, llamar
range(0, 1000000) resultará en más de 100 MB de
memoria utilizada.
Como alternativa, se puede implementar un generador xrange()
,
que sólo necesitará memoria para crear un
objeto Iterator y controlar el estado actual del
generador de manera interna, lo que no ocupa más de 1 kilobyte.
Ejemplo #1 Implementando range() como generador
<?php
function xrange($start, $limit, $step = 1) {
if ($start < $limit) {
if ($step <= 0) {
throw new LogicException('Step tiene que ser +ve');
}
for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step tiene que ser -ve');
}
for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}
/*
* Obsereve que tanto range() como xrange() producen la misma
* salida a continuación.
*/
echo 'Números impares de una cifra de range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";
echo 'Números impares de una cifra de xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}
?>
El resultado del ejemplo sería:
Números impares de una cifra de range(): 1 3 5 7 9
Números impares de una cifra de xrange(): 1 3 5 7 9
Cuando una función generadora es invocada por primera vez, se devuelve un
objeto de la clase interna Generator. Este objeto
implementa la interfaz Iterator de la misma forma
que lo haría un objeto iterador de solo avance, y proporciona métodos que pueden
ser invocados para manipular el estado del generador, incluyendo el envío
de valores hacia y la devolución de valores desde él.