PHP流式处理与生成器应用处理大文件或大数据集时一次性加载到内存会导致内存溢出。PHP的生成器和流式处理可以解决这个问题。今天说说怎么用生成器处理大数据。生成器用yield关键字可以在不生成整个数组的情况下进行迭代。每次迭代到yield时函数会暂停并保存状态下次迭代再继续。php// 生成器逐行读取大文件function readLargeFile(string $path): Generator{$handle fopen($path, r);if ($handle false) {throw new RuntimeException(无法打开文件: $path);}$lineNumber 0;while (($line fgets($handle)) ! false) {$lineNumber;yield $lineNumber trim($line);}fclose($handle);}// 使用生成器$file /tmp/large_file.txt;file_put_contents($file, implode(\n, range(1, 1000000)));$start memory_get_usage(true);foreach (readLargeFile($file) as $num $line) {if ($num % 100000 0) {echo 已处理 {$num} 行\n;}}echo 内存使用: . (memory_get_usage(true) - $start) / 1024 . KB\n;?生成器可以用于生成数据而不需要预先创建数组php// 生成所有数据的生成器function generateRange(int $start, int $end, int $step 1): Generator{for ($i $start; $i $end; $i $step) {yield $i;}}// 斐波那契数列生成器function fibonacci(int $limit): Generator{$a 0;$b 1;for ($i 0; $i $limit; $i) {yield $a;[$a, $b] [$b, $a $b];}}echo 斐波那契前10: ;foreach (fibonacci(10) as $num) {echo $num ;}echo \n;// 分页数据生成器function paginateGenerator(callable $fetcher, int $perPage 100): Generator{$page 1;while (true) {$items $fetcher($page, $perPage);if (empty($items)) break;foreach ($items as $item) {yield $item;}if (count($items) $perPage) break;$page;}}// 模拟从数据库分页查询function fetchFromDb(int $page, int $perPage): array{$start ($page - 1) * $perPage;if ($start 1000) return [];return array_map(fn($i) item_ . ($start $i), range(1, $perPage));}$count 0;foreach (paginateGenerator(fetchFromDb, 50) as $item) {$count;}echo 生成器获取了 {$count} 条数据\n;?生成器还可以用作协程实现简单的协作式多任务phpclass Task{private Generator $coroutine;private string $name;public function __construct(string $name, Generator $coroutine){$this-name $name;$this-coroutine $coroutine;}public function run(): bool{if ($this-coroutine-valid()) {echo 运行任务: {$this-name}\n;$this-coroutine-next();return true;}return false;}public function isFinished(): bool{return !$this-coroutine-valid();}}class Scheduler{private array $tasks [];public function add(Task $task): void{$this-tasks[] $task;}public function run(): void{while (!empty($this-tasks)) {$task array_shift($this-tasks);$task-run();if (!$task-isFinished()) {$this-tasks[] $task;} else {echo 任务完成\n;}}}}$scheduler new Scheduler();$scheduler-add(new Task(A, (function () {yield;echo 任务A步骤2\n;yield;echo 任务A步骤3\n;})()));$scheduler-add(new Task(B, (function () {yield;echo 任务B步骤2\n;yield;})()));$scheduler-run();?管道处理可以把多个生成器连接起来形成处理流水线phpfunction generateNumbers(int $count): Generator{for ($i 1; $i $count; $i) {yield $i;}}function filterEven(Generator $input): Generator{foreach ($input as $value) {if ($value % 2 0) {yield $value;}}}function multiply(Generator $input, int $factor): Generator{foreach ($input as $value) {yield $value * $factor;}}function limit(Generator $input, int $count): Generator{$i 0;foreach ($input as $value) {if ($i $count) break;yield $value;}}// 管道生成数字 - 过滤偶数 - 乘以3 - 取前5个$pipeline limit(multiply(filterEven(generateNumbers(100)),3),5);echo 管道处理结果: ;foreach ($pipeline as $value) {echo $value ;}echo \n;?生成器的内存优势很明显。生成一百万个数字的数组会占用几十MB内存而生成器只占几十字节。在处理大数据、大文件、大量数据库记录时生成器是非常有用的工具。