php[024]生成器

在 php 中有生成器这个东西。 官方的描述是

1
2
生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。

以及官方提供的改造range的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
function xrange($start, $limit, $step = 1) {
if ($start <= $limit) {
if ($step <= 0) {
throw new LogicException('Step must be positive');
}

for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be negative');
}

for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}

/*
* 注意下面range()和xrange()输出的结果是一样的。
*/

echo 'Single digit odd numbers from range(): ';
foreach (range(1, 9, 2) as $number) {
echo "$number ";
}
echo "\n";

echo 'Single digit odd numbers from xrange(): ';
foreach (xrange(1, 9, 2) as $number) {
echo "$number ";
}

在我第一次看到的时候并没有思考为什么叫生成器这个东西。所以在一段时间内产生了迷惑。其实用官方编写的函数样本赋值给变量var_dump出来的结果会是一个对象,而其生成器的名字是因为其可以通过foreach在循环的每次成产出结果。所以可以看以下代码,来感受以下yield解决了什么问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
function xrange($start, $limit, $step = 1) {
if ($start <= $limit) {
if ($step <= 0) {
throw new LogicException('Step must be positive');
}

for ($i = $start; $i <= $limit; $i += $step) {
yield $i;
}
} else {
if ($step >= 0) {
throw new LogicException('Step must be negative');
}

for ($i = $start; $i >= $limit; $i += $step) {
yield $i;
}
}
}

$xarr = xrange(0,9,1);
// 可以理解 $xarr 并不能用 一些数组切割的方式去做一些事情,因为其本身不是数组。
foreach($xarr as $v){
echo $v;
}
// 所以上述整体是做了这个
for($i = 0 ;$i<10;$i++){
echo $i;
}

$arr = range(0,9,1);
foreach($arr as $v){
echo $v;
}


以及更好看的文件读取编码方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function readTxt()
{
# code...
$handle = fopen("./test.txt", 'rb');

while (feof($handle)===false) {
# code...
yield fgets($handle);
}

fclose($handle);
}

foreach (readTxt() as $key => $value) {
# code...
echo $value.'<br />';
}

所以在某种程度,我更倾向于,这是一个特殊写法的语法糖。可以在某些方式上以优雅的形式去实现代码。