Performance Considerations in WP Stagecoach

One of the big things I have thought about while writing WP Stagecoach is how to make the plugin run as quickly as possible.

I would rather spend extra time and code in making the end product perform better than writing shorter or sometimes more readable code. On several occasions while I have been developing WP Stagecoach, I have taken time to test different methods of doing something to see which is faster. I am impressed by how little difference there is in performance between using different methods of doing things, despite being an interpreted language (rather than a compiled one).

However, a good example of where this is not the case recently came up in the PHP scandir() function. It returns an array of all the files and directories in a given directory, and on a unix-like system (like most web-hosting servers) that includes the current directory (‘.’) and the parent directory (‘..’), which are usually not used.

In WP Stagecoach, when the plugin creates a staging site, it first needs to scan the entirety of the WordPress install, and it does that by crawling over the filesystem, which means it runs scandir() a lot! I wanted to make sure that this was as fast as possible, so I tested the performance of several ways of excluding ‘.’ and ‘..’ from a foreach() loop over the array of files the plugin gets from scandir().

The cleanest and perhaps most obvious way seems to be to use array_diff() to remove the two unneeded dirs before the foreach() loop:
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
$arr = array_diff($array, array('.','..'));
foreach( $arr as $file ){
echo $file;
}
}

An alternative is to do a simple if( $file != ‘.’ && $file != ‘..’ ) for each element in the foreach loop. I was surprised how much faster this was than using the array_diff().
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
foreach ($array as $file) {
if( $file != '.' && $file != '..' ){
echo $file;
}
}

As it turns out, a third option seems to be even faster–using array_search() and unset() to remove the ‘.’ and ‘..’ entries from the array gotten from scandir().
$array = scandir('.');
for ($i=0; $i < 20000; $i++) {
unset( $array[ array_search('.', $array) ]);
unset( $array[ array_search('..', $array) ]);
foreach( $array as $file ){
echo $file;
}
}

In a loop of 20,000, using array_diff() was the slowest, with the simple if() conditionals running it about 10% faster, and unsetting the results of array_search being about 25% faster. On average, in a directory with ~150 items over a loop of 20k, the array_diff took 4.12s, using if’s took 3.73s and unsetting the values in the array took 3.30s.

While that may not seem like much, but every little bit helps (especially on slower web hosts) to make WP Stagecoach a bit more reliable and quick!