php生成器是 PHP5.5.0引入的功能,往往没有被充分利用,其实这是非常有用的功能,很多开发者并不知道生成器,因为生成器的作用不是很明显,生成器就是简单的迭代器,仅此而已。
与标准的PHP迭代器不同,PHP生成器不要求实现 Iterator 接口,从而减轻了类的负担,生成器会根据需求计算并产出要迭代的值,这对应用的性能有重大影响。
注意: PHP生成器不能满足所有迭代的需求,如果不查询,生成器是不知道下一个要迭代的值是什么,生成器也不能后退或快进,生成器还是一次性的,无法多次迭代一个生成器。如果需要多次操作可以克隆或重建生成器。
创建生成器
生成器创建方式很简单,因为生成器就是PHP 函数,只不过要在函数内一次或多次使用 yield 关键字,与普通函数不同的是,生成器只产出值,从不返回值。如示例:
一个简单的生成器
function myGenerator(){
yield '冬瓜';
yield '香瓜';
yield '西瓜';
}
在调用 生成器函数时,PHP 会返回一个属于 Generator 类的对象 ,这个对象可以直接用 foreach() 函数迭代。每次迭代,PHP会要求 Generator 实例计算并提供下一个要迭代的值。生成器的优雅体现于,每次产出一个值之后,生成器的内部状态都会停顿,向生成器请求下一个值时,内部状态又会恢复。生成器的内部状态会一直在停顿和恢复之间切换,直接抵达函数定义体的末尾或遇到空的 return;
调用并迭代 上面定义的生成器:
加上分隔符 ‘-’ 可以更直观看到,每次调用只产出一个值。
foreach (myGenerator() as $value) {
echo $value, '-';
}
输出:
冬瓜-香瓜-西瓜-
打印生成器函数
print_r(myGenerator());
输出:Generator Object ( )
使用生成器
下面实现一个简单的函数,用于生成一个范围内的数值,以此说明 PHP 生成器是如何节省内存的,首先,我们使用常规(错误)方式使现:
生成一个零至一百万范围内的数值
function makeRange($length) {
$dataset = [];
for ($i=0; $i< $length; $i++){
$dataset[] = $i;
}
return $dataset;
}
$customRange = makeRange(1000000);
foreach ($customRange as $value) {
echo $value;
}
以上的代码也能完成功能,但是并不是一个好的示范,代码并没有善用内存,makeRange() 函数要为预先创建的由一百万个整数组成的数组分配内存。而使用 PHP 生成器操作完成相同的功能,不需要为一百万个整数分配内存,仅为一个整数分配内存即可实现,示例:
function makeRange2($length){
for($i=0; $i<$length; $i++){
yield $i;
}
}
foreach (makeRange2(1000000) as $value) {
echo $value;
}
很明显的是,以上例题,PHP生成器能更轻松的实现,因为生成器不需要把一百万个数字加载到内存当中。
使用 PHP 生成器计算斐波那契数列也是一个很好的例子,我们还可以迭代流资源,假如我想要迭代一个大小为 4GB的 CSV 文件,而我们购买的虚拟私有服务器(VPS) 只允许PHP 使用 1GB内存,因此将整个文件加载到内存中是行不通的。使用生成器完成此例题:
function getRows($file){
$handle = fopen($file, 'rb');
if($handle === false){
throw new Exception();
}
while(feof($handle) === false){
yield fgetcsv($handle);
}
}
foreach (getRows('data.csv') as $row) {
print_r($row);
}
原文件和最终输出:

上述示例一次只会为CSV文件中的一行分配内存,而不会把整个 4GB 的 CSV 文件都读取到内存中,且上述代码把迭代的实现方式封装到一个简洁的包中,因此,可以很方便的调用。
生成器是功能多样性和简洁之间的折中方案。生成器是只能向前进的迭代器,这意味着不能使用生成器在数据集中执行后退、跳过、快进或查找操作,只能让生成器产生下一个值。迭代大型数据集或数列时最适合使用生成器,因为这样占用的系统内存量极少。
如果需要更多功能,例如在数据集执行后退、快进或查找操作,最好自己编写类,实现 Iterator 接口参考(http://php.net/manual/class.iterator.php)
更多示例参考 安东尼.费拉拉写的文章 What Generators Can Do For You (http://bit.ly/ircmaxwell)
文章参考: Modern PHP (中文版) 第2章
本文介绍了PHP生成器,它是PHP5.5.0引入的功能,是简单的迭代器,不要求实现Iterator接口,能按需计算产出迭代值,对性能有重大影响。文中说明了生成器的创建方式,通过示例展示其使用,如生成数值范围、计算斐波那契数列、迭代大文件等,指出其适合迭代大型数据集或数列。
634

被折叠的 条评论
为什么被折叠?



