stoPHPwatch
benchmark PHP functions and MySQL database SELECT queries

This page will host a battery of tests to compare, in real time, the speed of varying approaches to doing the same job in PHP and MySQL, to check if and which is the fastest alternative.
All benchmarks are ran on page load, you will notice varying absolute times for the tests, what's important is how they compare, usually the fastest will stay the fastest and same can be said for the slowest.

Execution times are calculated as delta of microtime(true); they are also normalized by setting the slowest time as 100, to be represented as bars of proportional length; shorter bars represent faster routines.

1. Loop structures

If you exclude foreach which is oriented towards array processing, pure looping structures in PHP are for, while and the least common do-while, which is a "reverted check" while.
An empty loop is repeated 5000 times.

do-while (source code)
75µs
<?php 
$testname='do-while';
$t0=microtime(true);
$i=0;
do {$i++;} while ($i<5000);
return microtime(true)-$t0;
?>
while (source code)
79µs
<?php 
$testname='while';
$t0=microtime(true);
$i=0;
while ($i<5000) {$i++;}
return microtime(true)-$t0;
?>
for (source code)
93µs
<?php
$testname='for';
$t0=microtime(true);
for ($i=0;$i<5000;$i++) {}
return microtime(true)-$t0;
?>

do-while is the fastest, even if this is not going to make a huge difference.
Take into consideration that the condition checking, in the former, is done at the end of the cycle, so it is going to run once more than while and for.

2. Operators to increment a variable

Integer increment operators are mainly used in looping routines, so together with the choice of the loop, comes this other alternative.
Here each operation is reiterated 5000 times.

++$i (source code)
58µs
<?php 
$testname='++$i';
$t0=microtime(true);
$i=0;
while ($i<5000) {
	++$i;
}
return microtime(true)-$t0;
?>
$i++ (source code)
71µs
<?php 
$testname='$i++';
$t0=microtime(true);
$i=0;
while ($i<5000) {
	$i++;
}
return microtime(true)-$t0;
?>
$i=$i+1 (source code)
78µs
<?php 
$testname='$i=$i+1';
$t0=microtime(true);
$i=0;
while ($i<5000) {
	$i=$i+1;
}
return microtime(true)-$t0;
?>
$i+=1 (source code)
83µs
<?php 
$testname='$i+=1';
$t0=microtime(true);
$i=0;
while ($i<5000) {
	$i+=1;
}
return microtime(true)-$t0;
?>

The pre-increment operator is the fastest, the extended addition operation is the slowest (even at typing it); pre-increment and postincrement are not functionally the same, so unless it doesn't matter for what you're trying to do, decide which one actually suits your needs.

3. Get the last element from a monodimensional non-associative array

end(); (source code)
55µs
<?php 
$testname='end();';
include "res/arrayrandmono.php";
$t0=microtime(true);
$i=0;
do {
	$last=end($array1);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
$array[count()-1]; (source code)
71µs
<?php 
$testname='$array[count()-1];';
include "res/arrayrandmono.php";
$t0=microtime(true);
$i=0;
do {
	$last=$array1[count($array1)-1];
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
end();reset(); (source code)
102µs
<?php 
$testname='end();reset();';
include "res/arrayrandmono.php";
$t0=microtime(true);
$i=0;
do {
	$last=end($array1);
	reset($array1);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>

If you just need to get the last element out of an array, and then forget about it, end() is the fastest; since end() moves the pointer to the end of the array though, if you need to access it again you may need to issue a reset(), which then makes it slower than the $array[count($array)-1] method.
Then again, if you don't need to repeat this kind of operation for a lot of times (and I don't see why you should do that) speed differences do not really matter... I was just curious to see which was faster :P

4. Get the last element from a multidimensional non-associative array

end(); (source code)
45µs
<?php 
$testname='end();';
include "res/arrayrandmulti.php";
$t0=microtime(true);
$i=0;
do {
	$last=end($array4);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
$array[count()-1]; (source code)
66µs
<?php 
$testname='$array[count()-1];';
include "res/arrayrandmulti.php";
$t0=microtime(true);
$i=0;
do {
	$last=$array4[count($array4)-1];
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
end();reset(); (source code)
90µs
<?php 
$testname='end();reset();';
include "res/arrayrandmulti.php";
$t0=microtime(true);
$i=0;
do {
	$last=end($array4);
	reset($array4);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>

General considerations here are the same of the previous test; the difference though is that with multidimensional arrays (it was a bidimensional here) the $array[count($array)-1] method is the fastest of the three.

5. String substitution (single token) on big string (~130kb .html, 103 occurrences)

str_replace(); //"~mytoken" tokens (source code)
419µs
<?php 
$testname='str_replace(); //"~mytoken" tokens';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokentildesingle.html");
$i=0;
do {
	$cleantext=str_replace("~mytoken","hokuto",$bigstring);
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>
str_replace(); //"{mytoken}" tokens (source code)
422µs
<?php 
$testname='str_replace(); //"{mytoken}" tokens';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokencurly.html");
$i=0;
do {
	$cleantext=str_replace("{mytoken}","hokuto",$bigstring);
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>
str_replace(); //"~mytoken~" tokens (source code)
483µs
<?php 
$testname='str_replace(); //"~mytoken~" tokens';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokentilde.html");
$i=0;
do {
	$cleantext=str_replace("~mytoken~","hokuto",$bigstring);
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>
str_replace(); //"%mytoken%" tokens (source code)
550µs
<?php 
$testname='str_replace(); //"%mytoken%" tokens';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokenpercent.html");
$i=0;
do {
	$cleantext=str_replace("%mytoken%","hokuto",$bigstring);
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>
str_replace //"<!--mytoken-->" tokens (source code)
781µs
<?php 
$testname='str_replace //"&lt;!--mytoken--&gt;" tokens';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokencomment.html");
$i=0;
do {
	$cleantext=str_replace("<!--mytoken-->","hokuto",$bigstring);
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>
sprintf(); //"%1$s" tokens, pre-existing "%" replaced with "%%" (source code)
1841µs
<?php 
$testname='sprintf(); //"%1$s" tokens, pre-existing "%" replaced with "%%"';
$t0=microtime(true);
$bigstring=file_get_contents("res/bightmltokensprintf.html");
$i=0;
do {
	$cleantext=sprintf($bigstring,"hokuto");
	++$i;
} while ($i<20);
return microtime(true)-$t0;
?>

String substritution is used mainly in templating; most templating routines use str_replace() on curly braces {tokens}, while on my own home-made template engine for my other websites, I tend to adopt tilde ~tokens~.
This and the next test are atypical, in the fact that there is just one token repeated several times inside the string, while templates usually have more than one token lying in the HTML code.
PHP also offers a builtin function in the form of sprintf(), which you may think is faster than "vanilla" str_replace(), because, you know, it's builtin, but this test surprised me, as sprintf() is the slowest by quite a measure.
Some considerations are in order about the delimiters you choose for your tokens: templating substitution is going to happen mostly in HTML files, that already contain < and > symbols, also they may contain percent sign (%) as part of URL encoding, so str_replace() is going to get confused if also your own tokens start with the same characters (hence, using HTML comments as tokens is not really a good idea).
Using uncommong characters as token delimiters speeds things up, that's why tilde and curly braces are fastest. Usually the "single tilde" (~token instead of ~token~) is even slighly faster, because you're halving the number of occurrences for the delimiter character inside the string, but since the advantage is minimal, and not even always there, there is no point in using it. Also, having a second delimiter at the end of the token string helps avoiding confusion, for example, between ~comment and ~commentauthor.

6. String substitution (single token) on small string (~2kb .html, 3 occurrences)

str_replace //"~mytoken~" tokens (source code)
150µs
<?php 
$testname='str_replace //"~mytoken~" tokens';
$t0=microtime(true);
$smallstring=file_get_contents("res/smallhtmltokentilde.html");
$i=0;
do {
	$cleantext=str_replace("~mytoken~","hokuto",$smallstring);
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
preg_replace //"~mytoken~" tokens, case insensitive modifier (source code)
201µs
<?php 
$testname='preg_replace //"~mytoken~" tokens, case insensitive modifier';
$t0=microtime(true);
$smallstring=file_get_contents("res/smallhtmltokentilde.html");
$i=0;
do {
	$cleantext=preg_replace("/~mytoken~/i","hokuto",$smallstring);
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
preg_replace //"~mytoken~" tokens (source code)
280µs
<?php 
$testname='preg_replace //"~mytoken~" tokens';
$t0=microtime(true);
$smallstring=file_get_contents("res/smallhtmltokentilde.html");
$i=0;
do {
	$cleantext=preg_replace("/~mytoken~/","hokuto",$smallstring);
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
sprintf(); //"%1$s" tokens, pre-existing "%" replaced with "%%" (source code)
449µs
<?php 
$testname='sprintf(); //"%1$s" tokens, pre-existing "%" replaced with "%%"';
$t0=microtime(true);
$smallstring=file_get_contents("res/smallhtmltokensprintf.html");
$i=0;
do {
	$cleantext=sprintf($smallstring,"hokuto");
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
str_ireplace //"~mytoken~" tokens (source code)
460µs
<?php 
$testname='str_ireplace //"~mytoken~" tokens';
$t0=microtime(true);
$smallstring=file_get_contents("res/smallhtmltokentilde.html");
$i=0;
do {
	$cleantext=str_ireplace("~mytoken~","hokuto",$smallstring);
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>

Nothing to add to the previous test's considerations... sprintf() is still the very slowest.
This time though, I added the case-insensitive str_ireplace() just for the sake of it, to show how it is slower than str_replace() since it must take into account also variations between lowercase and uppercase letters, but I am just pointing out the obvious here.
Same goes for preg_replace(), slower than str_replace(), but it's worth to note than its case-insensitive counterpart (using the appropriate pattern modifier) is faster than str_ireplace() and practically equivalent to the case sensitive regular expression substitution; so if case-inseneitive is what you need, preg_replace() is the way.

7. Sentence substitution, single token (UI translation oriented)

sprintf //"%s" (source code)
98µs
<?php 
$testname='sprintf //"%s"';
$t0=microtime(true);
$sentence="The quick brown %s jumps over the lazy dog";
$i=0;
do {
	$cleantext=sprintf($sentence,"fox");
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
str_replace //"%s" (source code)
130µs
<?php 
$testname='str_replace //"%s"';
$t0=microtime(true);
$sentence="The quick brown %s jumps over the lazy dog";
$i=0;
do {
	$cleantext=str_replace("%s","fox",$sentence);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
preg_replace //"%s" (source code)
246µs
<?php 
$testname='preg_replace //"%s"';
$t0=microtime(true);
$sentence="The quick brown %s jumps over the lazy dog";
$i=0;
do {
	$cleantext=preg_replace("/%s/","fox",$sentence);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>

Finally sprintf() makes sense. It is indeed better than the alternatives (albeit by a small amount) when substituting strings like "Goodmorning %s!" and "Buongiorno %s!", that is sentences of a UI you need translated, and that contain one token, usually representing a date, or a name, or whatever.

8. Multiple tokens string substitution inside a small paragraph (9 tokens, 1 occurence each)

Another kind of substitution is the one of several different tokens at the same time, in a small string, for example a template for a part of a webpage.
I will compare sprintf() both with numbered (%1$s %2$s %n$s) and unnumbered tokens (%s), and str_replace() with the same numbered tokens.

sprintf //"%n$s" (source code)
133µs
<?php 
$testname='sprintf //"%<i>n</i>$s"';
$t0=microtime(true);
$paragraph=file_get_contents("res/tokenizedpar.txt");
$i=0;
do {
	$cleantext=sprintf($paragraph,'The','quick','brown','fox','jumps','over','the','lazy','dog');
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
sprintf //"%s" (source code)
186µs
<?php 
$testname='sprintf //"%s"';
$t0=microtime(true);
$paragraph=file_get_contents("res/tokenizedparnan.txt");
$i=0;
do {
	$cleantext=sprintf($paragraph,'The','quick','brown','fox','jumps','over','the','lazy','dog');
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>
str_replace //"%n$s" (source code)
452µs
<?php 
$testname='str_replace //"%<i>n</i>$s"';
$t0=microtime(true);
$paragraph=file_get_contents("res/tokenizedpar.txt");
$i=0;
do {
	$search=array('%1$s','%2$s','%3$s','%4$s','%5$s','%6$s','%7$s','%8$s','%9$s');
	$replace=array('The','quick','brown','fox','jumps','over','the','lazy','dog');
	$cleantext=str_replace($search,$replace,$paragraph);
	++$i;
} while ($i<200);
return microtime(true)-$t0;
?>

And here sprintf() really shines; with unnumbered tokens the substitution is even faster (and utterly unreadable/difficult to mantain), so if you have only a few, unrepeated tokens that will always stay in the same order, you can squeeze some more performance just using %s.
If mantainability is a must, str_replace() (with descriptive tokens starting with unique characters) is still a welcomed option.

9. Format number with leading zero(es)

Sometimes you have to format a long series of numbers so they take all the same amount of digits (read: leading zeroes).
str_pad() is thought exactly for this purpose, but an old friend pops up, sprintf(), with its numeric formatting.

sprintf (source code)
116µs
<?php 
$testname='sprintf';
$t0=microtime(true);
$i=0;
do {
	$n=sprintf("%010d", $i); 
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>
str_pad (source code)
138µs
<?php 
$testname='str_pad';
$t0=microtime(true);
$i=0;
do {
	$n=str_pad($i, 10, "0", STR_PAD_LEFT);
	++$i;
} while ($i<1000);
return microtime(true)-$t0;
?>

sprintf() is faster, not by a lot, but still enough to make a difference; implementing it takes even less keystrokes than str_pad(), so why not.

17ms