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
<?php 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中使用協程實現多任務調度”這一主題中,該主題偏難,而我對它的理解也只是到了簡單的任務調度這一塊
而更高級的內容,再慢慢了解。
為什么它能完成任務的調度呢?關於這一點可類比操作系統中的程序中斷,在那里,中斷的作用則就是為了任務調度。
如何使用yield來完成任務調度,這一