Search This Blog

8/13/2011

Foreach vs. For

performance

Last year, at a PHP mailing list discussion, I was surprised with the information that the loop structure "for" was faster than "foreach". After, I receive the source of that information: The PHP Benchmark. The site's author said the "for" is faster for write operations, but is slower for reading traveled items. Taking a look at the source-code, I came to the conclusion it was wrong a little strange.

In fact, the "foreach" is faster than the "for" to read, because it uses an internal "iterator" that walk at each memory block using a memory pointer. At the other hand, the structure "for" needs to use the brackets operator to get the value of each index, and this operatator needs to travel from the begining of array to the desired index. The random-access of the brackets operator makes it slow.

The problem is that the site said it occurs the inverse for the write operations: the "for" is faster than "foreach" (search for "Modify Loop" at site). Taking a look at the source-code used for comparision, I found the problem. Take a look at a simplified version of the source-code:

// FOR
$count = count($array);
for ($i = 0; $i < $count; ++$i) {
    $array[$i] = 1;
}

// FOREACH
foreach ($array as $i => $value) {
    $array[$i] = 1;
}

It is logical that "for", in this case, was faster. Look at the internal operations of each structure: they are identical. But, at each iteration, the "for" does only 2 operations: compares two numbers and increments a variable, while the "foreach" does (at least) 5 operations: advances the internal pointer, gets the index, sets the index to the variable $i, gets the value of the pointer, sets the value to the variable $value. So: the "foreach" made more operations than the "for", and was slower (as expected).

However, it does not make sense to use a "foreach" only to get its indexes and use them with brackets operator to modify its values. The better way is to use "foreach" with reference operator, because it would not be needed to use the brackets operator. The source-code would get as below:

// FOREACH WITH REFERENCE
foreach ($array as &$value) {
    $value = 1;
}

Yes. Now the "foreach" is faster than the "for" (it is also faster than the "foreach" without reference operator). This was the test that the author forgot to show at his site and he came to a incomplete conclusion.

Therefore, in my opinion, the "foreach" is always faster than the "for" when the objective is to work with the read or write in traveled values from the array. As the target of the "foreach" is read or write in the traveled items, I do not see contraindications to its use.

But when we should use a "for"?
Easy: when you need to initialize a value, make comparision to determine the stop time, and need to make operations to walk to the next iteration. For example: to walk from number X to Y, getting the values of its positions of an array.

And what is the problem of "foreach"?
The traditional "foreach" works with a copy of the array (or object) sent to them. It means you will need the double memory usage. It could exceed the memory limit and your script would stop. But, for common situations, the "foreach" is very useful.

Well, this post is also written to alert who believe at all (or almost all) that is read. In the computer area is need to take a very critic look, including the empiric results, because there could be many details to consider. This blog is also open to critics and should not be treated as an absolute true. If you disagree with something, you are welcome to put a comment.

No comments:

Post a Comment