最近從用了2年多的Yii轉到了Yii2,讀了一遍官方文檔以后發現兩個比較有趣的新函數,each()和batch()都是歸於db方面的,看了下源碼然后寫了點拙見。
先看源碼,each()和batch()函數都是調用BatchQueryResult這個類,唯一的區別是each這個參數,而這個類它實現了Iterator接口,這也就說明了為什么each和batch都要用foreach來調用。


簡單說下Iterator,這個接口是PHP預定義的接口,同時它繼承於Traversable預定義接口,這個接口唯一的作用就是檢測一個類是否可以使用 foreach 進行遍歷。
回過來再看BatchQueryResult這個類,主要的兩個可以配置的屬性each和batchSize, each就是用來區別each和batch的屬性,主要表現在next()這個函數上,仔細看了下代碼,其實發現each和batch的區別就是foreach每次取出的數據量,而這個數據量受限於batchSize,默認是100,接下來再看源碼又會發現each和batch都是一次性取出上限batchSize的數據,區別只不過是foreach遍歷單次輸出的數據each是每次一條,batch每次batchSize條。

具體實現細節看fetchData這個函數,這里本質是填充數據,獲取數據調用的是 _dataReadeder->read(), 追蹤函數會發現其實調用的是PDO::fetch()函數,限制獲取數量的條件是batchSize,到這里each()和batch()其實是一樣的,具體這兩個函數的區別要看next()函數:

理解這里可以先看下官方文檔關於foreach調用時的內部實現(
https://www.php.net/manual/zh/class.iterator.php),這邊可以看出本質上each()和batch()每次都取出batchSize個數據,但是區別是each()在遍歷時候每次只取出一個,batch()直接返回batchSize個數據,所以如果對內存有要求不管each()還是batch()都要按需限制下batchSize參數。