問題描述
foreach(explode(',' $foo) as $bar) { ... }
對比
$test = explode(',' $foo);
foreach($test as $bar) { ... }
在第一個例子中,它是在每次迭代時explode
$foo
字符串還是PHP 將它保存在內存中并在它自己的臨時變量中爆炸?從效率的角度來看,創建額外的變量 $test
是否有意義,或者兩者幾乎相等?
In the first example, does it explode
the $foo
string for each iteration or does PHP keep it in memory exploded in its own temporary variable? From an efficiency point of view, does it make sense to create the extra variable $test
or are both pretty much equal?
推薦答案
我可以做出有根據的猜測,但讓我們嘗試一下!
I could make an educated guess, but let's try it out!
我認為有三種主要方法可以解決這個問題.
I figured there were three main ways to approach this.
- 在進入循環之前爆炸并賦值
- 在循環中爆炸,沒有賦值
- 字符串標記化
我的假設:
- 可能由于分配而消耗更多內存
- 可能與 #1 或 #3 相同,不確定哪個
- 可能更快,內存占用也小得多
方法
這是我的測試腳本:
Approach
Here's my test script:
<?php
ini_set('memory_limit', '1024M');
$listStr = 'text';
$listStr .= str_repeat(',text', 9999999);
$timeStart = microtime(true);
/*****
* {INSERT LOOP HERE}
*/
$timeEnd = microtime(true);
$timeElapsed = $timeEnd - $timeStart;
printf("Memory used: %s kB
", memory_get_peak_usage()/1024);
printf("Total time: %s s
", $timeElapsed);
這里是三個版本:
1)
// explode separately
$arr = explode(',', $listStr);
foreach ($arr as $val) {}
2)
// explode inline-ly
foreach (explode(',', $listStr) as $val) {}
3)
// tokenize
$tok = strtok($listStr, ',');
while ($tok = strtok(',')) {}
結果
看起來有些假設被推翻了.你不愛科學嗎?:-)
Looks like some assumptions were disproven. Don't you love science? :-)
- 總的來說,這些方法中的任何一種對于合理大小"(幾百或幾千)的列表來說都足夠快.
- 如果您要迭代巨大的內容,時間差異相對較小,但內存使用量可能會相差一個數量級!
- 當你
explode()
在沒有預賦值的情況下內聯時,由于某種原因它會慢一點. - 令人驚訝的是,標記化比顯式迭代聲明的數組慢.在如此小的規模上工作,我相信這是由于每次迭代對
strtok()
進行函數調用的調用堆棧開銷.更多內容請參見下文.
- In the big picture, any of these methods is sufficiently fast for a list of "reasonable size" (few hundred or few thousand).
- If you're iterating over something huge, time difference is relatively minor but memory usage could be different by an order of magnitude!
- When you
explode()
inline without pre-assignment, it's a fair bit slower for some reason. - Surprisingly, tokenizing is a bit slower than explicitly iterating a declared array. Working on such a small scale, I believe that's due to the call stack overhead of making a function call to
strtok()
every iteration. More on this below.
就函數調用的數量而言,explode()
ing 確實是標記化的佼佼者.O(1) vs O(n)
In terms of number of function calls, explode()
ing really tops tokenizing. O(1) vs O(n)
我在運行方法 1) 的圖表中添加了一個獎勵,并在循環中調用了一個函數.我使用了 strlen($val)
,認為這將是一個相對相似的執行時間.這是有爭議的,但我只是想提出一個一般性的觀點.(我只運行了 strlen($val)
并忽略了它的輸出.我沒有沒有將它分配給任何東西,因為分配會增加額外的時間成本.)>
I added a bonus to the chart where I run method 1) with a function call in the loop. I used strlen($val)
, thinking it would be a relatively similar execution time. That's subject to debate, but I was only trying to make a general point. (I only ran strlen($val)
and ignored its output. I did not assign it to anything, for an assignment would be an additional time-cost.)
// explode separately
$arr = explode(',', $listStr);
foreach ($arr as $val) {strlen($val);}
正如您從結果表中看到的那樣,它成為三種方法中最慢的方法.
As you can see from the results table, it then becomes the slowest method of the three.
這很有趣,但我的建議是做任何你認為最易讀/最可維護的事情.只有當您真正處理非常大的數據集時,您才應該擔心這些微優化.
This is interesting to know, but my suggestion is to do whatever you feel is most readable/maintainable. Only if you're really dealing with a significantly large dataset should you be worried about these micro-optimizations.
這篇關于在 foreach 循環參數中分解數組的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!