Is while faster than foreach in core?
| Project: | Drupal |
| Version: | x.y.z |
| Component: | base system |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | won't fix |
Description
I recently read this:
foreach is convenient, but doing a while(list($key, $value) = each($var)) is way faster and less memory intensive because foreach makes a copy of the array before it cycles where each just moves the pointer
A colleague seemed to confirm in tests that this was the case. So I set out to test the theory in core. Here is a patch that replaces almost every single foreach with while for all of the files in includes.
I tried to test on my localmachine with ab, but it wasn't cooperating. If someone else could do some benchmarking on this patch, it'd be appreciated. Testing different pages (like admin/user/access) is important.
And if anyone has any tips on getting ab working with MAMP, drop me a line.
| Attachment | Size |
|---|---|
| while.patch | 48.48 KB |

#1
Here's a demo script of the difference between foreach and while,list,each. Change the comment on lines 119 and 120 when you run it.
There is one big catch to look for when you change away from foreach - reset()ing the array pointer before you read the array again. Since foreach copies the array before looping, you don't have to worry about the array pointer.
#2
http://de2.php.net/manual/en/control-structures.while.php#35022
This comment seems to show that the real truth is somewhat subtler and will take more thought than just replacing all foreach loops with while.
#3
And based on these benchmarks, it would seem that while is in fact a step backwards:
http://byster.net/?page_id=48
#4
Interestingly, according to those same benchmarks, sizeof is faster than count in PHP5:
http://byster.net/?page_id=48#a7
#5
Re #4, I'm skeptical about that since sizeof is supposed to be an alias to count.
#6
On something like this:
function drupal_map_assoc($array, $function = NULL) {if (!isset($function)) {
$result = array();
- foreach ($array as $value) {
+ while (list($value) = each($array)) {
That implemenation of
list()is only correct if the key and value are the same, otherwise $value would actually have the value of the array's key becauseeach()returns an array of the key as a value and the value as a value.#7
I've run a patch through ab that has this change in menu.inc and didn't see any obvious changes.
The patch (for 4.7) is attached.
#8
I think our optimization efforts are better spent elsewhere. Closing. Thanks for testing, killes.