PHP 生成器Generator理解

不言
發布: 2023-03-24 07:26:02
原創
1482 人瀏覽過

這篇文章介紹的內容是關於PHP 生成器Generator理解,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

轉載整理自:寄凡、風雪之隅、PHP手冊

可解決的問題





  • #        引用自官網:生成器提供了一種更容易的方法來實現簡單的物件迭代,相比較定義類別實作Iterator介面的方式,效能開銷和複雜度大大降低。生成器允許你在foreach程式碼區塊中寫程式碼來迭代一組資料而不需要在記憶體中創建一個數組,那會使你的記憶體達到上限(劃重點),或者會佔據可觀的處理時間。相反,你可以寫一個生成器函數,就像一個普通的自定義函數一樣,和普通函數只返回一次不同的是, 生成器可以根據需要 yield 多次,以便生成需要迭代的值。

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空是一個有效的語法並且它將會終止生成器繼續執行。 ##################        yield只能在函數中使用,否則會回報PHP Fatal error:The "yield" expression can only be used inside a function,凡是使用了yiel關鍵字的函數都會傳回一個Generator物件。每次程式碼執行到yield語句都會中止執行,返回yield語句中表達式的值給Generator對象,繼續迭代Generator對象時,yield後面的程式碼會接著執行,直到所有yield語句全部執行完畢或者有return語句,這個renturn語句只能回傳null,即return;,否則會編譯錯誤。 ############從實例出發理解執行過程和可使用函數############        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 實例中二### ###
<?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 生成器Generator理解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!