PHP的生成器

2021-08-13 12:58:06 字數 4198 閱讀 8319

參考文章:

php生成器是5.5.0引入的功能,生成器實際上就是簡單的迭代器。生成器會根據需求計算產出迭代的值,而標準的php迭代器經常在記憶體中執行迭代操作,這要預先計算出資料集,效能較低。如果使用特定的防護計算大量資料,可以使用生成器,即時計算並產出後續值,不占用記憶體。

yield和生成器

相比較迭代器,生成器提供了一種更容易的方法來實現簡單的物件迭代,效能開銷和複雜性都大大降低。

乙個生成器函式看起來像乙個普通的函式,不同的是普通函式返回乙個值,而乙個生成可以yield生成許多它所需要的值,並且每一次的生成返回值只是暫停當前的執行狀態,當下次呼叫生成器函式時,php會從上次暫停的狀態繼續執行下去

function

xrange

($start, $end, $step = 1)

}foreach (xrange(1, 1000000) as

$num)

我們在使用生成器的時候可以像關聯陣列那樣指定乙個鍵名對應生成的值。如下生成乙個鍵值對與定義乙個關聯陣列相似。

function

xrange

($start, $limit, $step = 1)

}$xrange = xrange(1, 10, 2);

foreach ($xrange

as$key => $value)

實際上生成器函式返回的是乙個generator物件,這個物件不能通過new例項化,並且實現了iterator介面。

generator implements iterator
可以看到出了實現iterator的介面之外generator還新增了send方法,用來向生成器傳入乙個值,並且當做yield表示式的結果,然後繼續執行生成器,直到遇到下乙個yield後會再次停住。

function

printer

() }

$printer = printer();

$printer->send('hello');

$printer->send('world');

以上的例子會輸出:

receive: hello

receive: world

在上面的例子中,經過第乙個send()方法,yield表示式的值變為hello,之後執行echo語句,輸出第一條結果receive: hello,輸出完畢後繼續執行到第二個yield處,只不過當前的語句沒有執行到底,不會執行輸出。如果將例子改改就能夠看出來yield的繼續執行到**。

function

printer

() }

$printer = printer();

$printer->send('hello');

$printer->send('world');

這次的輸出便會變為:

this

is the yield

1receive: hello

this

is the yield

2receive: world

this

is the yield

3

上面的流程我簡單說下:第一步執行$printer->send('hello');進入while迴圈,先輸出this is the yield 1然後輸出receive: hello之後i+

+,i變為2,然後由於while(true)又再次迴圈,還是先輸出this is the yield 2(因為現在$i已經是2了),

然後執行到echo 'receive: ' . yield; 由於現在**沒有給他send()了,所以就執行到這停止了;然後就執行第二步$printer->send('world');這裡是關鍵,第二次send後,他會從上次暫停的狀態繼續執行下去。所以就執行**echo 'receive: ' . yield;對應結果是receive: world,然後i+

+,i變為3,迴圈沒有結束,執行echo 'this is the yield ' . $i;對應結果是this is the yield 3

這邊可以清楚的看出send之後的繼續執行到第二個yield處,之前的**照常執行。

我們再對例子進行適當的修改:

function

printer

() }

$printer = printer();

var_dump($printer->send('first'));

var_dump($printer->send('second'));

執行一下會發現結果為:

this

is the yield first

int(2)

this

is the yield second

int(3)

讓我們來看一下,是不是發現了問題,跑出來的結果不是從1開始的而是從2開始,這是為啥嘞,我們來分析一下:

在此之前我們先來跑另外一段**:

function

printer

() }

$printer = printer();

var_dump($printer->current());

var_dump($printer->send('first'));

var_dump($printer->send('second'));

這個時候我們會發現執行的結果變成了:

int(1)

this

is the yield first

int(2)

this

is the yield second

int(3)

可以看到在第一次呼叫生成器函式的時候,生成器已經執行到了第乙個yield表示式處,所以在$printer->send('first')之前,生成器便已經yield 1出來了,只是沒有對這個生成的值進行接收處理,

在send()了之後,echo語句便會緊接著完整的執行,執行完畢繼續執行$i++,下次迴圈便是var_dump(2)。

至此,我們看到了yield不僅能夠返回資料而且還可以接收資料,而且兩者可以同時進行,此時yield便成了資料雙向傳輸的工具,這就為了實現協程提供了可能性。

補充:

<?php

class

generator

implements

iterator

?>

function

xrange()}

$a = xrange();//返回乙個生成器

echo

$a->current();//返回當前產生的值 結果為11

//列印的結果11,不是因為echo $a.'

';這句導致的,而是(yield '11')這句,之前一直以為是echo $a的結果

//如果這個時候在echo $a->current();後面加一句$a->send('33');

function

xrange()}

$a = xrange();//返回乙個生成器

echo

$a->current().'

';//返回當前產生的值

$a->send('33');//向生成器中傳入乙個值,並且當做 yield 表示式的結果,然後繼續執行生成器。

其結果:

ppp11

33ppp

//當執行echo $a->current().'

';的時候結果是:

ppp11

這個時候暫停在$a = (yield

'11'); 這裡,隨後執行$a->send('33'),在暫停點繼續執行,結果是:

33ppp

至於接下來的協程的知識,水平有限不好介紹,還是看鳥哥的原文比較直接,裡面例子很豐富,介紹的很詳盡。

生成器 PHP的生成器yield 原創

在php 5.5中,php多了乙個新的特性,那就是生成器 generator 生成器提供了一種更簡單的方法來實現簡單的物件迭代。下面的manual的引用 生成器提供了一種更容易的方法來實現簡單的物件迭代,相比較定義類實現 iterator 介面的方式,效能開銷和複雜性大大降低。生成器允許你在 for...

php的生成器

如果是做python或者其他語言的小夥伴,對於生成器應該不陌生。但很多php開發者或許都不知道生成器這個功能,可能是因為生成器是php 5.5.0才引入的功能,也可以是生成器作用不是很明顯。但是,生成器功能的確非常有用。直接講概念估計你聽完還是一頭霧水,所以我們先來說說優點,也許能勾起你的興趣。那麼...

php之生成器

引用手冊 乙個生成器函式看起來像乙個普通的函式,不同的是普通函式返回乙個值,而乙個生成器可以yield生成許多它所需要的值。當乙個生成器被呼叫的時候,它返回乙個可以被遍歷的物件.當你遍歷這個物件的時候 例如通過乙個foreach迴圈 php 將會在每次需要值的時候呼叫生成器函式,並在產生乙個值之後儲...