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;
}

WordPress, WP E-Commerce and the lack of ASYNC AJAX

Now Normally the A in AJAX means Asynchronous, meaning you can have several requests going at once, so it was very confused as to why my AJAX wasn’t. My WordPress plugin is a long running import process and I decided to use AJAX so that I can provide timely feedback to the user as to how far the import had gotten.

But these status updates were not working. I would get the entire output at the end of the process.

Then it dawned on me. WP E-Commerce is a pig and assumes that you want a session started all the time (even if you do not need it – which is rather bad for varnish caching), and PHP sessions are blocking, so that only one call with the same session id is handled at a time. AJAX sends cookies, and therefore WP E-Commerce starts the same session for all session requests.

So remember, if you are writing a long running plugin with lots of AJAX requests and you are not getting async output, check to see if there is a session cookie being sent!

The way I solved this problem is to use this code at the top and bottom of your plugin!

if ($_COOKIE['PHPSESSID']) {
	session_write_close();
}

if ($_COOKIE['PHPSESSID']) {
	session_start();
}