PHP 生成器详解
生成器是 PHP 中一种强大的迭代器,它允许你用更少的代码和更少的内存来处理大量数据。

基本概念
生成器允许你在循环中迭代数据,而不必提前创建整个数组,它使用 yield 关键字来返回值,而不是 return。
基础语法
<?php
// 基本生成器示例
function generateNumbers($start, $end) {
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
// 使用生成器
foreach (generateNumbers(1, 1000000) as $number) {
if ($number > 5) break;
echo $number . "\n";
}
键值对生成
<?php
// 生成键值对
function generateUser() {
yield 'name' => 'John';
yield 'email' => 'john@example.com';
yield 'age' => 30;
}
foreach (generateUser() as $key => $value) {
echo "$key: $value\n";
}
从生成器返回值
<?php
function generateData() {
yield '第一项';
yield '第二项';
return '生成器结束';
}
$generator = generateData();
foreach ($generator as $item) {
echo $item . "\n";
}
// 获取返回值
echo "返回值: " . $generator->getReturn() . "\n";
生成键值对处理数据库数据
<?php
// 模拟数据库查询结果
function getUsersFromDB() {
// 假设这是数据库查询结果
$users = [
['id' => 1, 'name' => '张三'],
['id' => 2, 'name' => '李四'],
['id' => 3, 'name' => '王五'],
];
foreach ($users as $user) {
yield $user;
}
}
// 不占用大量内存的处理
foreach (getUsersFromDB() as $user) {
echo "用户ID: " . $user['id'] . ", 名字: " . $user['name'] . "\n";
}
实用示例:处理大文件
<?php
// 逐行读取大文件
function readLargeFile($filePath) {
$file = fopen($filePath, 'r');
if (!$file) {
throw new Exception("无法打开文件");
}
while (($line = fgets($file)) !== false) {
yield trim($line);
}
fclose($file);
}
// 使用:处理超大文件而不占内存
try {
foreach (readLargeFile('/path/to/large/file.txt') as $line) {
// 处理每一行数据
echo $line . "\n";
}
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
生成器委托
<?php
// 生成器委托功能 (PHP 7+)
function subGenerator() {
yield '子生成器1';
yield '子生成器2';
}
function mainGenerator() {
yield '主生成器1';
// 委托给子生成器
yield from subGenerator();
yield '主生成器2';
}
foreach (mainGenerator() as $value) {
echo $value . "\n";
}
使用生成器创建无限序列
<?php
// 无限斐波那契数列
function fibonacci() {
$a = 0;
$b = 1;
while (true) {
yield $a;
$newB = $a + $b;
$a = $b;
$b = $newB;
}
}
$fib = fibonacci();
for ($i = 0; $i < 10; $i++) {
echo $fib->current() . " ";
$fib->next();
}
内存效率对比
<?php
// 传统方式(占用大量内存)
function getDataFromFile() {
$data = [];
$file = fopen('data.txt', 'r');
while (($line = fgets($file)) !== false) {
$data[] = trim($line);
}
return $data;
}
// 生成器方式(高效内存使用)
function getDataFromFileGenerator() {
$file = fopen('data.txt', 'r');
while (($line = fgets($file)) !== false) {
yield trim($line);
}
}
// 对比内存使用
$memory1 = memory_get_peak_usage();
$data = getDataFromFile();
$memory2 = memory_get_peak_usage();
echo "传统方式内存: " . ($memory2 - $memory1) . " bytes\n";
$memory3 = memory_get_peak_usage();
foreach (getDataFromFileGenerator() as $line) {
// 处理数据
}
$memory4 = memory_get_peak_usage();
echo "生成器方式内存: " . ($memory4 - $memory3) . " bytes\n";
注意事项
- 生成器只能单向迭代:不能回退或跳转
- 不能生成字符串:只能用于循环结构
- 不能被克隆:生成器对象不能使用 clone 关键字
- 需要 PHP 5.5+:至少 PHP 5.5 版本才支持生成器
最佳实践
<?php
// 最佳实践示例:数据处理管道
function readCSV($filePath) {
$file = fopen($filePath, 'r');
while (($row = fgetcsv($file)) !== false) {
yield $row;
}
fclose($file);
}
function filterData($generator, $callback) {
foreach ($generator as $key => $value) {
if ($callback($value)) {
yield $key => $value;
}
}
}
function transformData($generator, $callback) {
foreach ($generator as $key => $value) {
yield $key => $callback($value);
}
}
// 链式处理
$data = readCSV('data.csv');
$filtered = filterData($data, function($row) {
return $row[2] > 100;
});
$transformed = transformData($filtered, function($row) {
$row[3] = $row[0] + $row[1];
return $row;
});
foreach ($transformed as $row) {
print_r($row);
}
生成器是处理大数据集的强大工具,合理使用可以显著提高代码效率和内存使用率。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播