Представим, что нам надо распарсить какой-то гигантский документ и сформировать вставки в базу по 10к элементов. Для решения этой задачи не обязательно писать кастомный итератор, можно всё сделать "на коленке". Оборачиваем генератор с распарсенными данными в
NoRewindIterator, чтобы избежать его перемотки, а затем применяем LimitIterator до тех пор, пока не закончатся данные:
final readonly class Importer
{
private const BATCH_SIZE = 10_000;
public function __construct(private Connection $connection) {}
public function import(): void
{
foreach ($this->parseBatched() as $batch) {
$sqlValues = '';
$values = [];
foreach ($batch as $value) {
$sqlValues .= ($sqlValues === '' ? '' : ',') . '(?)';
$values[] = $value;
}
$this->connection->execute(
'insert into data (val) values ' . $sqlValues,
$values,
);
}
}
private function parseBatched(): Generator
{
$parsed = new NoRewindIterator($this->parse());
while ($parsed->valid()) {
yield new LimitIterator($parsed, limit: self::BATCH_SIZE);
}
}
private function parse(): Generator
{
// ...
}
}