1. 程式人生 > >php 迭代器與和生成器

php 迭代器與和生成器

php有很多功能強大的介面,其中ArrayAccess 與 Iterator 的配合使用可以讓物件與陣列一樣有著靈活的訪問性。

當然,用ArrayAccess 與 Iterator 配合可以用來對付陣列,但還有一個更好的辦法同則SPL 提供的ArrayIterator

原因就是 :

ArrayIterator implement ArrayAccess, SeekableIterator, Countable, Searializable {}

而接下來要介紹的則是Iterator的更高一層用法。

與Iterator有關的函式先記錄下

iterator_to_array() 把迭代器中的元素轉換成陣列

IteratorAggregate::getIterator() 呼叫一個外部迭代器

ArrayIterator

Iteartor_count() 等等

而php在使用Iterator介面則是迭代器模式的一種實現。在這裡,其中的概念客戶端(實現迭代過程)、迭代器、具體迭代器則會別對應於,foreach() , 繼承於iterator介面的具體類和需要遍歷的陣列或集合。

而生成器,則是建立在理解迭代器的基礎之上。

php中的生成器,可以叫做迭代生成器,因為它就是一個不可new的類,同時繼承Iterator,且多了一個send() 與 生成器通訊

它的實現則是通過yield關鍵字,或語句,或表示式,其工作方式則是,使用yield的結構體就是一個生成生成器類,當執行到yield

時,則中斷該生成器,並存儲其狀態,當再次執行(foreach 或 while等迴圈結構) , 則會恢復其狀態,並直到再次遇到yield

複製程式碼

function gen() {
    $ret = (yield 'yield1');
    var_dump($ret);
    $ret = (yield 'yield2');
    var_dump($ret);
}

$gen = gen();
var_dump($gen->current());    // output:string(6) "yield1" 當該生成器形成的時候
                              //rewind()就已經隱式的執行,即生成就已經到第一個yield中斷了
var_dump($gen->send('ret1')); // output:string(4) "ret1"   (the first var_dump in gen)
                              // 這時,send()則做了它該做的,恢復中斷,把值(ret1)傳入yield,並返回yield(ret1), 直到再遇到yield ,無則返回null
                              // output:string(6) "yield2" (the var_dump of the ->send() return value)
                             // 這時執行到$ret = (yields 'yield2'); 時則中磁芯,並把yield表示式的值返回,
                              //此時為 yield2 ,若沒有 後面的 ‘yield2’, 則會返回null
var_dump($gen->send('ret2')); //output:string(6) "yield2" (the var_dump of the ->send() return value)
                               // output:null
                   // 這時send()執行的時候 ,並沒有下一個yield則返回的是null,而其恢復執行後在函式體內有一個var_dump(),所以會有output

其實,由上面的例項可總結出兩點 ,

一是,初始化生成器時則已經到了一個yield,形成了中斷,

二是,send 的執行實際上是,先next() , 再vaild() , 不能過則return null, 通過則current() ,返回,若是yield 後沒有“預設”($ret = (yield 'default');),

則返回的是null,再進行中斷,直至再次恢復。

理解了它是如何工作的,則出現了一個實際的問題,它有什麼用呢?

生成器的高階使用出現在“在php中使用協程實現多工排程”這一主題中,該主題偏難,而我對它的理解也只是到了簡單的任務排程這一塊

而更高階的內容,再慢慢了解。

  為什麼它能完成任務的排程呢?關於這一點可類比作業系統中的程式中斷,在那裡,中斷的作用則就是為了任務排程。