Comparing a while loop against a foreach loop of an array

C

Are you confused by the title?  I was when I first got the idea to even write this blog as well.  I was recently perusing the CakePHP change logs and came across an interesting commit – Optimization for Hash Method.

The optimization is quite simple, this code:

[code]
while (($key = array_shift($parts)) !== null)
[/code]

Is replaced with the following code:

[code]
foreach ($parts as $key)
[/code]

This is actually done several times in the commit.  It seems that the original developer is really keen on using the array_shift function.  Just in seeing this code, I thought the original code was odd to utilize that function so I immediately had to do a comparison and validate the optimization!

 To start we need two basic files.  The first file will test using a while loop:

[code]
<?php
$start = microtime();
$array = array_fill(0, 100, ‘dummy_data’);

while ($key = array_shift($array) !== null) {
echo $key;
}

$end = microtime();
?>
<hr/>
Execution Time: <?php echo ($end – $start) ;?> seconds.
[/code]

The second file needs to then use a foreach  loop:

[code]
<?php
$start = microtime();
$array = array_fill(0, 100, ‘dummy_data’);

foreach ($array as $key) {
echo $key;
}

$end = microtime();
?>
<hr/>
Execution Time: <?php echo ($end – $start) ;?> seconds.
[/code]

Now that the basics are done, it’s time to pull out the recent A Simple But Effective Speed Comparison tool that I built earlier and running the comparison between the two files.

The results are a bit surprising, the while loop code executed about 6,000 times in 10 seconds.  Whereas the foreach loop code executed about 8,000 times in 10 seconds.  This equates to about a 25% improvement while looping through an array of 100 records.

I actually thought that using array_shift and assigning the results to a value, then checking that it is not null would be much slower compared to a foreach loop than just 25%.  It seems like it would have been much slower and in reality if the array was smaller it would be even more negligible of a difference.

At the end of the day, I think the foreach loop is more readable and would continue to use that regardless of the 25% speed increase…

About the author

  • http://twitter.com/tsewlliw Will West

    Don’t knock your expectations, I think you just missed a bit in your testing.

    There is a bug in one of the loops, such that the while loop prints out a bunch of 1’s and the foreach loop prints out ‘dummy_data’. The 10x difference in amount of I/O might be throwing off your timing.

    The other thing is that you may be testing on too small an array. I used a 10k array and the while loop took nearly 8x longer. (.195s foreach, 1.65s while)

    Then I redirected stdout to /dev/null, and the timings went to foreach: 0.028s; while: 1.081s.

    Now thats the difference that probably motivated the change — array_shift is O(N), making the while loop O(N^2).

    • endyourif

      The key here is a 10k array is probably outside of the example scenario that this code is pulled from. As mentioned in the article I pulled this code from a CakePHP optimization commit. The practical use of this code, the array probably wouldn’t have exceeded 100 elements.

  • endyourif

    Awesome feedback – thanks Will.

  • McBuckDGAF

    From 6,000 executions to 8,000 executions is a 33% improvement–not trying to nitpick, but it is an important difference.

By Jamie

My Books