你应该知道的 PHP yield 知识 ( 中 )

你应该知道的 PHP 生成器知识 ( 一 ) 中,我们可以发现,一个生成器函数和一个普通函数的最大区别,就是使用了 yield 语句。所以,掌握生成器,最重要的就是掌握 yield 语句

生成器语法

生成器从外观上看起来像是一个普通的函数,不同的是普通函数会一次性返回所有的序列值,使用相同的参数再次调用,返回的值和前一次相同。( 这是函数的基本要求 )。但生成器就不一样了,生成器一次只返回一个序列中的一个值。并在相同参数的再次调用,返回的是序列中的下一个值。

从另一个方面说,当一个生成器被调用的时候,它返回一个可以被遍历的对象。当我们使用 foreach 遍历这个对象的时候,PHP 将会在每次需要值的时候调用生成器函数,并在产生一个值之后保存生成器的状态。这样,在下一次调用的时候就可以恢复调用的状态。

一旦不需要生成更多的值,或者生成器已经不能生成更多的值,那么可以抛出一个 LogicException 异常简单的退出。调用生成器的代码会捕获这个异常,然后继续执行,就像一个数组已经被遍历完了一样。

注意

在 PHP 5 中,生成器函数不能用 return 语句显式的返回一个值,这回引发一个编译器错误。但空返回( return; )是允许的,一般用于终止生成器。

在 PHP 7 中,生成器函数可以使用 return 语句返回任意值,然后可以通过 Generator::getReturn() 方法来获取。

PHP yield 语句

一个生成器的核心是 yield 关键字。它最简单的使用方式看起来就是 return 语句,一个返回某个值的 return 语句。不同之处在于普通的 return 语句会返回值并终止函数的执行,而 yield 语句也会返回一个值,但只是简单的暂停此生成器函数的执行。这个不同造就了上面我们所提到的普通函数与生成器的差别。

我们一个范例来演示下 yield 语句这种特殊的返回暂停模式

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        //注意变量 $i 的值在不同的 yield 之间是保持传递的。
        echo "生成一个值 $i \n";
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}

运行结果如下

[yufei@www.twle.cn helloworld]$ php d.php
生成一个值 1 
1
生成一个值 2 
2
生成一个值 3 
3

对比下输出语句,foreach 语句每次对生成器函数的调用只返回一个值。

表达式语句中的 yield

我们还可以将 yield 语句生成的值赋值给一个变量。但需要注意的是,如果在一个表达式上下文(例如在一个赋值表达式的右侧)中使用 yield,必须使用圆括号把 yield 申明包围起来。 例如这样是有效的

$data = (yield $value);

但下面这样就不合法,在 PHP5 中会产生一个编译错误

$data = yield $value;

但在 PHP 中,圆括号是可以省略的,上面这条语句也不会报错。而且这种语法特别有用,因为它可以和 Generator::send() 函数配合使用。

yield 生成一个键值对

PHP 中的生成器,除了生成简单的值外,还可以生成一个键值对。生成键值对的方式和定义一个关联数组的方式十分相似,如下所示

<?php
function gen_alpha() {
    $alpha = explode(' ', 'a b c d e f g h i j k l m n o p q r s t u v w x y z');
    for ($i = 1; $i <= 10; $i++) {
        yield $i => $alpha[$i%26];
    }
}

$generator = gen_alpha();
foreach ($generator as  $k => $v) {
    echo $k, " => ", $v, "\n";
}

运行结果如下

[yufei@www.twle.cn helloworld]$ php d.php
1 => b
2 => c
3 => d
4 => e
5 => f
6 => g
7 => h
8 => i
9 => j
10 => k

注意

和表达式语句中的 yield 一样,在一个表达式上下文中生成键值对也需要使用圆括号进行包围,例如

 $data = (yield $key => $value);

空 yield 语句

一个空 yield 语句将会返回一个 NULL 值。

例如下面这段代码演示的

<?php
function gen_three_nulls() {
    foreach (range(1, 3) as $i) {
        yield;
    }
}

foreach ( gen_three_nulls() as $v )
{
    var_dump($v);
}

运行结果如下

[yufei@www.twle.cn helloworld]$ php d.php
NULL
NULL
NULL

yield 生成一个引用值

生成函数可以像使用值一样来使用引用生成。使用方式和从函数返回一个引用一样:通过在函数名前面加一个引用符号。

通过这种引用生成的方式,我们可以在生成器外部控制生成器的退出时机。

<?php


function &gen_reference() {
    $value = 3;

    while ($value > 0) {
        yield $value;
    }
}

/* 
 * 我们可以在循环中修改$number的值,而生成器是使用的引用值来生成,所以gen_reference()内部的$value值也会跟着变化。
 */
foreach (gen_reference() as &$number) {
    echo (--$number).'... ';
}

输出结果如下

2... 1... 0... 
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.