ホームページ  >  記事  >  バックエンド開発  >  PHP ジェネレーター ジェネレーターの理解

PHP ジェネレーター ジェネレーターの理解

不言
不言オリジナル
2018-04-17 09:35:291484ブラウズ

この記事で紹介されている内容は、PHP ジェネレーターの理解に関するものであり、必要な友人に参考にしていただけます。

転載元: Jifan、Fengxuezhiyu、PHP マニュアル。ジェネレーター



    解決できる問題


公式ウェブサイトから引用: ジェネレーターは、クラスを定義してイテレーター・インターフェース・アプローチ、パフォーマンスのオーバーヘッド、および複雑さが大幅に軽減されます。ジェネレーターを使用すると、メモリ内に配列を作成せずに、foreach ブロックにコードを記述してデータ セットを反復処理できます。これにより、メモリの制限に達したり (強調を追加)、かなりの処理時間がかかってしまいます。代わりに、通常のカスタム関数と同じようにジェネレーター関数を作成できます。通常の関数が 1 回だけ返すのではなく、ジェネレーターは反復する必要がある値を生成するために必要なだけ何度でも生成できます。


    Generate は、Iterator インターフェイスを実装します。
  • <?php
    //生成器
    Generator implements Iterator {
        //返回当前产生的值
        public mixed current ( void )
        //返回当前产生的键
        public mixed key ( void )
        //生成器继续执行
        public void next ( void )
        //重置迭代器,如果迭代已经开始了,这里会抛出一个异常。
        public void rewind ( void )
        //向生成器中传入一个值,当前yield接收值,然后继续执行下一个yield
        public mixed send ( mixed $value )
        //向生成器中抛入一个异常
        public void throw ( Exception $exception )
        //检查迭代器是否被关闭,已被关闭返回 FALSE,否则返回 TRUE
        public bool valid ( void )
        //序列化回调
        public void __wakeup ( void )
        //返回generator函数的返回值,PHP version 7+
        public mixed getReturn ( void )
    }
    ?>
    キーワード yield
  • ジェネレーター関数の中核は、yield キーワードです。最も単純な形式では、これは return ステートメントのように見えますが、通常の return は値を返して関数の実行を終了するのに対し、yield はジェネレーターをループするコードに値を返し、ジェネレーター関数の実行を単に一時停止する点が異なります。ジェネレーターは値を返すことができません。値を返すとコンパイル エラーが発生します。ただし、return null は有効な構文であり、ジェネレータの実行を終了します。 ️利回りのみを使用できます関数内で使用しないと、PHP 致命的エラーが報告されます。「yield」式は関数内でのみ使用でき、yield キーワードを使用する関数は Generator オブジェクトを返します。コードが yield ステートメントまで実行されるたびに、実行が一時停止され、yield ステートメントの式の値が Generator オブジェクトに返されます。Generator オブジェクトの反復を続けると、yield の後のコードが引き続き実行されます。すべての yield ステートメントが実行されるか、return ステートメントが存在するまで、renturn ステートメントは null (つまり return; ) のみを返すことができ、それ以外の場合はコンパイル エラーが発生します。


例をもとに実行の流れと使える機能を理解する


1 例1

<?php
function xrang($start, $end, $step=1){
    for($i=$start; $i<=$end; $i += $step) {
        yield $i;  //yield关键字定义了中断点
    }   
}


//foreach (xrang(1, 10000) as $num) {
//  echo $num."\n"; 
//}


$rang = xrang(1,2);
var_dump($rang).PHP_EOL; //输出: object(Generator)#1 (0) {}
var_dump($rang instanceof Iterator).PHP_EOL; //输出: bool(true)


$key = $rang->key(); 
var_dump("key: ".$key).PHP_EOL; //输出: string(6) "key: 0"
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(8) "valid: 1"
$current = $rang->current();
var_dump("current: ".$current).PHP_EOL; //输出: string(10) "current: 1"


$rang->next();


$key = $rang->key(); 
var_dump("key: ".$key).PHP_EOL; //输出: string(6) "key: 1"
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(8) "valid: 1"
$current = $rang->current();
var_dump("current: ".$current).PHP_EOL; //输出: string(10) "current: 2"


$rang->next();


$key = $rang->key();
var_dump("key: ".$key).PHP_EOL; //输出: string(5) "key: "
$valid = $rang->valid();
var_dump("valid: ".$valid).PHP_EOL; //输出: string(7) "valid: "


//$rang->rewind(); //重置,目前看到的所有文档中,rewind()仅在第一次调用Generator的时候隐式执行。生成器开始迭代后调用会抛出Fatal error。
?>
    2 例2
  • <?php
    function gen(){
        echo "1111\n";
        $ret = (yield &#39;yield1&#39;);
        var_dump($ret);
        echo "2222\n";
        $ret = (yield &#39;yield2&#39;);
        var_dump($ret);
        //return;
    }
    $gen = gen();
    var_dump($gen->current()).PHP_EOL;
    $a = $gen->send(&#39;ret1&#39;);
    echo "66666\n";
    var_dump($a).PHP_EOL;
    echo "77777\n";
    var_dump($gen->valid()).PHP_EOL;
    $b = $gen->send(&#39;ret2&#39;);
    var_dump($b).PHP_EOL;
    var_dump($gen->valid()).PHP_EOL;
    
    
    //1111
    //string(6) "yield1"
    //string(4) "ret1"
    //2222
    //66666
    //string(6) "yield2"
    //77777
    //bool(true)
    //string(4) "ret2"
    //NULL
    //bool(false)
    ?>

        2.1 执行过程为:

            1.首先调用gen(),进入函数输出1111,执行到第一个yield关键字所在的位置中断(此时yield表达式的值为定义的"yield1",使用current()获取当前表达式的值即得到string(6) "yield1")
            2.调用send()方法向生成器中传入值"ret1"(传入生成器的值.这个值将会被作为生成器当前所在的 yield 的返回值),此时生成器从当前所在的yield表达式开始迭代,程序继续往下执行   
            3.遇到var_dump输出当前表达式的值"ret1",继续执行输出2222
            4.继续执行,程序来到第二个yield中断点,此时表达式的值为定义值"yield2",因为调用的是send()方法,该方法返回当前所在的yield的值(current()方法值)。(查看send方法的官方文档)
            5.$a获取到send方法的返回值即"yield2",继续执行输出"66666", $a, "77777"
            6.输出当前生成器是否可用
            7.继续执行,向生成器中传入值"ret2",生成器开始继续迭代。此时生成器位于第二个yield表达式,该表达式接受"ret2"作为返回值赋予变量$ret,打印得到string(4) "ret2"。
            8.打印之后,$b == NULL,为NULL的原因因为未彻底理解清楚(疑问之处在于此时的send()方法到底有没有返回NULL),猜测可能有如下两个原因:
                8.1 一者可能是因为生成器之后没有中断点,也没有返回值(返回值不被允许,或者说仅允许返回return; return;用于终止生成器的执行),$gen->send()方法根本就没有返回任何东西,导致$b == NULL
               8.2 二者可能是$gen->send('ret2')传入值后,生成器迭代完本次的yield,隐式调用了next()和current(),又因为next()下面没有yield中断点使得current()返回NULL,导致send()返回值为NULL
                 8.3 根据上下文,二的可能性更大


        2.2 关于send()方法
            send()向生成器中传入一个值,并且当做 yield 表达式的结果,然后继续执行生成器。如果当这个方法被调用时,生成器不在 yield 表达式,那么在传入值之前,它会先运行到第一个 yield 表达式。            

    相关推荐:

    PHP生成器的功能与用法详解

    php生成器详细介绍

以上がPHP ジェネレーター ジェネレーターの理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。