4.4 生成器(Generator)與yield
前面在1.1.8小節講述過迭代器。一個迭代器是這樣一個容器,它實現了Traversable接口,從而能夠遍歷容器中的內部元素。PHP中最常見的迭代器是數組,能使用foreach來遍歷所有的元素。
與迭代器密切相關的概念是生成器(Generator)和yield。
4.4.1 生成器
為了解釋生成器,我們先看一個現實中的例子。
假設某工廠有5000名工人,為解決就餐問題開設了食堂,每餐每人有1碗米飯1盤菜。工人打飯時有兩個方案:
方案1:食堂工作人員把5000份套餐全部打包好,放在桌子上,依次發給工人。
方案2:工人排隊,食堂工作人員依次給工人打飯。
現實生活中第1種方案并不常見,因為事先把所有套餐全部打包好,需要占用餐廳5000個位置來放置這些飯盒,很浪費空間;而采用第2種方案,米飯和菜只需分別放在一個大桶里,隨用隨取即可。
將這個例子放到程序里可以有如下表示:
1.數組里有5000個元素

2.采用自定義的生成函數生成
(源碼文件:ch04/generator.php)

采用memory_get_usage方法打印出兩種方案所需的內存使用量:
方案1:968912
方案2:226504
可以看到方案2的內存使用量僅是方案1的1/4。方案2也有其他優點:實現簡單,1個人就可以打飯;方案1裝滿5000份套餐所需時間太長,后面裝好前面就涼了,方案2隨用隨取。
生成器是用來生成迭代器的函數,其優點有以下三個:
● 實現簡單。
● 避免分配大塊內存,防止程序超過內存限制。
● 避免生成迭代器的執行時間過長。
4.4.2 yield
yield應用于生成器函數里,類似于return,但略有不同:
● yield可以有多個。
● yield會記住上次返回的值,下次調用時會返回下一個yield。
例如以下示例中,有3個yield,每次遍歷時會依次返回1,2,3的值,從而實現遍歷。
(源碼文件:ch04/yield_demo)

4.4.3 生成器的設計
Generator可以生成一個可迭代的容器,顯然這個容器的容量是有限的。那么設計生成器時,就引出一個問題:是由Generator控制數目,還是在循環中控制呢?這里分享一個規則:
● 規則1:當數據有一定規則可循時,可以由Generator控制數目。例如生成奇數,計算階乘等。
● 規則2:當數據無規則可循或隨機時,一般在循環中控制。
為了便于理解,我們實現兩個Generator。
1.生成奇數
編寫一個函數,當輸入n時,輸出n個奇數。
程序代碼如下:(源碼文件:ch04/generator_odd.php)

2.生成uuid
uuid是通用唯一識別碼(Universally Unique Identifier),理論上每個uuid都是全局唯一的,這在生成不重復的標識符時非常有用,如訂單號、物流號。按照概率論計算,一個人每年被隕石擊中的概率大概是170億分之一,而兩個uuid重復的概率比這還小。
程序示例如下:(源碼文件:ch04/generator_uuid.php)

這個例子中,采用外部變量$num來控制遍歷的數目,一旦達到數量限制,遍歷過程會被break,從而控制了循環的流程。
4.4.4 面試題:用yield實現斐波那契數列
題目描述:輸入n,返回斐波那契數列的前n個數,要求用yield實現。
解答:斐波那契數列的每一項都是前兩個數之和,例如:
0,1,1,2,3,5,8,13,...
實現代碼如下:(源碼文件:ch04/yield_fibonacci.php)

引申思考:為什么不用遞歸實現斐波那契數列呢?
遞歸實現斐波那契數列的確比較簡單,但存在重復計算的問題;而yield實現(這種方法叫動態規劃)時,能夠暫存子問題的結果,因此效率更高些。
- Progressive Web Apps with React
- Microsoft Exchange Server PowerShell Cookbook(Third Edition)
- Object-Oriented JavaScript(Second Edition)
- Windows Phone 7.5:Building Location-aware Applications
- Creating Mobile Apps with jQuery Mobile(Second Edition)
- iPhone應用開發從入門到精通
- Mastering Concurrency Programming with Java 9(Second Edition)
- 監控的藝術:云原生時代的監控框架
- 用Python動手學統計學
- INSTANT LESS CSS Preprocessor How-to
- Java面向對象程序設計教程
- Laravel 5.x Cookbook
- 軟件測試項目實戰之功能測試篇
- C++面向對象程序設計教程
- Building Microservices with .NET Core 2.0(Second Edition)