PHP: for vs foreach

So this week I was asked the question on which was quicker in PHP – A for loop or a foreach loop. It turns out that my assertion that they were both about the same performance was about right. Here are my test results

jason@server:~/php$ php speedtest.php
Starting test: Test for loop data length=4000000
     Mem: 795.63MiB Used
Peak Mem: 795.63MiB Used
[xxxxxxxxx ]
Results for test Test for loop data length=4000000
Min   : 0.6085901260376
Max   : 0.61222791671753
Mean  : 0.6110053062439
StdDev: 0.00015155474344889

     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
Starting test: Test foreach loop data length=4000000
     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
[xxxxxxxxx ]
Results for test Test foreach loop data length=4000000
Min   : 0.41838312149048
Max   : 0.42730903625488
Mean  : 0.42159442901611
StdDev: 0.0010704358418783

     Mem: 795.63MiB Used
Peak Mem: 795.64MiB Used
On average test 2 is faster than test 1 by 1.4493x

And the code I used to run the test is:

<?php

$data_length = 4000000;//rand(10000000,20000000);
for ($i=0; $i<$data_length; $i++) {
        $data[] = $i;
}


$avg1 = run_test("Test for loop data length={$data_length}", "test_for",&$data);
$avg2 = run_test("Test foreach loop data length={$data_length}", "test_foreach",&$data);

print "On average ";
if ($avg1 < $avg2) {
        print "test 1 is faster than test 2 by ";
        printf("%0.4fx\n", $avg2 / $avg1);
} else {
        print "test 2 is faster than test 1 by ";
        printf("%0.4fx\n", $avg1 / $avg2);
}


function test_for(&$data) {
        $max = count(&$data);
        for($i=0; $i<$max; $i++) {$x=&$data[$i];}
}

function test_foreach(&$data) {
        foreach ($data as &$x) {}
}


function run_test($name, $func, &$data) {
        print "Starting test: $name\n";
        printf("     Mem: %3.2fMiB Used\n", memory_get_usage()/1024/1024);
        printf("Peak Mem: %3.2fMiB Used\n", memory_get_peak_usage()/1024/1024);
        $num_runs = 10;

        for($i=0; $i<$num_runs; $i++) {
                print "[" . str_repeat('x',$i) . str_repeat(' ',$num_runs-$i) . "]\r";
                $run_times[] = time_run($func,&$data);
        }

        print "\nResults for test {$name}\n";
        $min = null;
        $max = null;
        $mean = null;
        foreach ($run_times as $run_time) {
                $mean += $run_time;
                $max = (is_null($max) || $run_time > $max) ? $run_time : $max;
                $min = (is_null($min) || $run_time < $min) ? $run_time : $min;
        }
        $mean /= $num_runs;

        // now work out the std deviation aka confidence
        $std_dev_count = 0;
        foreach ($run_times as $run_time) {
                $dev = $run_time - $mean;
                $std_dev_count = $dev * $dev;
        }
        $std_dev = sqrt( $std_dev_count / ($num_runs-1));

        print "Min   : {$min}\n";
        print "Max   : {$max}\n";
        print "Mean  : {$mean}\n";
        print "StdDev: {$std_dev}\n\n";

        printf("     Mem: %3.2fMiB Used\n", memory_get_usage()/1024/1024);
        printf("Peak Mem: %3.2fMiB Used\n", memory_get_peak_usage()/1024/1024);

        return $mean;
}

function time_run($func,&$data) {
        $start = microtime(1);
        $func(&$data);
        $end = microtime(1);
        return $end - $start;
}