简介
生成器是另一种可迭代的对象,为了迭代一组数据,可以将数据存入一个数组,或者由一个实现了Iterator接口的对象来表示。但两种方式要么需要占用大量内存,要么太过于繁琐。而生成器则是第三种方式。在php中,生成器实际是一种内置类,即Generator类。不过使用生成器却不是直接通过此类的构造函数来构造一个可迭代的Generator对象,而是由yield关键字来生成,并由一个函数来返回此Generator对象。例如:
function yd() {
$arr = [1,2,3];
yield $arr[0];
yield $arr[1];
yield $arr[2];
}
该函数运行结束后将返回一个Generator对象,而函数中yield执行了多少次,就可以从返回的Generator对象中迭代出多少数值。不过并不是在函数执行完毕后生成器中就包含了所有数据,实际上数据是在迭代过程中生成的。如果yield没有参数,则表示返回一个null。
注意,返回的对象只能被迭代一次,再次迭代将会出错,当然,每次执行函数都可以得到一个新的生成器。
function yd($max=0) {
if($max < 0)
throw new Exception();
for($i=0; $i<=$max; $i++) {
yield $i;
}
}
$a = yd(5);
foreach ($a as $d) {
echo "$d ";
}
// 再次执行以下代码将出错
//foreach ($a as $d) {
// echo "$d ";
//}
如果需要在生成器函数中控制yield的执行,可以使用无参数的return语句来结束函数,如果使用带参数return语句,返回的值可由getReturn()方法获取。
function yd($max=0) {
$i = 0;
if($max < 0)
throw new Exception();
for(;;) {
yield $i++;
if($i>$max) break;
}
}
当一个生成器被调用的时候,它返回一个可以被遍历的对象.当你遍历这个对象的时候(例如通过一个foreach循环),PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态,这样它就可以在需要产生下一个值的时候恢复调用状态。也就是说生成器对象中并没有保存全部迭代值。
function yd()
{
yield 0;
yield 1;
yield 2;
return 3;
return 4;
return 5;
}
$a = yd();
foreach ($a as $v) {
echo "$v \n";
}
echo "getReturn: ".$a->getReturn();
/*
0
1
2
getReturn: 3
*/
生成器可以以“键-值”对的形式返回
function yd($max=0) {
$i = 0;
if($max < 0)
throw new Exception();
for(;;) {
yield $i => $i * 2;
if(++$i * 2 > $max) break;
}
}
foreach (yd(8) as $k => $v) {
echo "$k => $v \n";
}
/*
0 => 0
1 => 2
2 => 4
3 => 6
4 => 8
*/
生成器函数可以返回一个引用
在下例中,迭代的变量通过引用返回并由外部修改。
function &yd($max=0) {
$i = 0;
if($max < 0)
throw new Exception();
for(;;) {
yield $i;
if($i > $max) return;
}
}
foreach (yd(8) as $k => &$v) {
echo "$k => $v \n";
$v += 3;
}
/*
0 => 0
1 => 3
2 => 6
*/
使用yield from语句从另一个生成器、数组或可迭代对象中获取值
function count_to_ten()
{
yield 1;
yield 2;
yield from [3, 4];
yield from new ArrayIterator([5, 6]);
yield from seven_eight();
return yield from nine_ten();
}
function seven_eight()
{
yield 7;
yield from eight();
}
function eight()
{
yield 8;
}
function nine_ten()
{
yield 9;
return 10;
}
$gen = count_to_ten();
foreach ($gen as $num) {
echo "$num ";
}
echo "\ngetReturn: ";
echo $gen->getReturn();
注意,在本例中,通过getReturn()方法得到了返回值10,其中nine_ten()和count_to_ten()都使用了return语句,这两个return语句缺一不可,否则将无法从getReturn()中获取返回值。