Increasing PHP performance
Friday, 13 July 2007
This is just a short post on a couple of performance increases you can do in your code that was kindly pointed out to me by WhiteAcid, when he looked through the source code of my captcha. I must admit I wasn’t aware of these slight improvements and I’m sure this post will inform a few people of the potential performance gains. I’ve haven’t done any benchmarking on the following examples so if anyone knows of a good PHP benchmarking site, please send it in and I shall include the link here.
Conditions
The triple equals sign increases performance because PHP performs a strict check on the two variables.
<?php
if($variable1 === $variable2) {
//code
}
?>
Concatenation
I usually concat a string with the following:-
<?php
echo '';
?>
But a better way is to use commas to output the string because PHP only has to output it instead of using concatenation.
<?php
echo '';
?>
Benchmarks
I found this excellent site with some benchmark tests:-
PHP benchmarks
Also this on string benchmarking:-
String benchmarks
For vs while
Loops
Yet another benchmark, this one is quite comprehensive:-
Speed freaks
That’s all for now, I might include some more examples at a later time.
Timing class by Richard Heyes
Have you got any performance tips you’d like to share? Leave a comment and I shall get in touch and choose the best ones which will be added to this post.
No. 1 — July 13th, 2007 at 3:14 pm
The second point is a common subject of controversy.
Some benchmarks show the opposite. Facing comma separated arguments, PHP issues as manu ‘echo’ as there are arguments (at least in some 4.* versions).
Example :
Is the same as
This can lead to a slower execution speed compared to the classic concatenated one.
According to some PHP experts, the real fastest way for concatenated input is to use the implode() native PHP function.
Example :
But seriously, the speed gain is so tiny regarding other potential application bottlenecks than it is better to opt for the most modular approach. And the comma separated output is quite inflexible.
For example, with coma separated arguments, you can not switch from an ‘echo’ statement to a variable assignation.
Example
Believe me, it’s not a minor point. I still remember that I had to refactor a big application for a better separation between process and display. The previous code was full of coma separated echo statements. It took weeks to get rid of them.
Hugues
No. 2 — July 13th, 2007 at 3:51 pm
Very good points Hugues, I think the decision is with the programmer to choose which option is best depending on the task.
No. 3 — July 13th, 2007 at 6:15 pm
Why not just do some actual tests about your intutions on the command-line?
$ time -f \%es php -r “\$var1 = ‘foo’; \$var2 = ‘bar’; for(\$i=0; \$i /dev/null
1.58s
$ time -f \%es php -r “\$var1 = ‘foo’; \$var2 = ‘bar’; for(\$i=0; \$i /dev/null
1.08s
Clearly, strict equals wins, as one would expect.
However,
$ time -f \%es php -r “\$var = ‘foo’; for(\$i=0; \$i /dev/null
1.88s
$ time -f \%es php -r “\$var = ‘foo’; for(\$i=0; \$i /dev/null
1.00s
Hugues is right, concatentation wins, with a greater improvement than the strict equals.
Unfortunately, implode() is really slow, counter to his advice.
$ time -f \%es php -r “\$var = ‘foo’; for(\$i=0; \$i /dev/null
2.21s
No. 4 — July 15th, 2007 at 8:32 am
1. Use single quotes instead of double quotes for strings wherever possible. This saves the parser the overhead of searching for variables inside double quoted text.
2. Use ++$i instead of $i++. The second one uses a temporary copy of $i to add 1 to, then assign to $i.
3.
No. 5 — July 15th, 2007 at 12:00 pm
dancaragea excellent tips! Thanks very much for sharing them
No. 6 — July 16th, 2007 at 10:00 am
dancaragea:
the for-loop that you consider as the fastest has one major drawback: it only works, if the array is continously numerated. You’ll run into problems, if there is a gap.
will only output the array contents to “4”.
that was the only thing i wanted to say to this 😉
No. 7 — July 16th, 2007 at 10:34 am
We now have syntax colouring 🙂
I hope you don’t mind but I edited some of your comments to help format and add syntax colouring. Thanks to everyone for the excellent feedback!
No. 8 — July 16th, 2007 at 10:41 am
Robin I don’t think you’re correct because the isset function would be using the index not the value to see if the next array item exists. So it doesn’t matter if a value is removed.
Unless I’m misunderstanding your point?
No. 9 — July 16th, 2007 at 10:56 am
Hi,
I’m right, test the code and you’ll see what I mean. You want see the “6” in the output, because if $i get’s the value “4” and so isset checks isset($array[4]) and returns false and the loop breaks.
$i does not know magically the index of the next item, it just gets increased.
So the point is: If you haven’t a continously numerated array and want to get the for-loop into all contents of it, you can’t use the solution above.
Hmm, or are we misunderstanding us each other? Don’t know, because of the tropical heat here I haven’t found much sleep the last days 😉
No. 10 — July 16th, 2007 at 11:13 am
I Checked the code and yes I see what you mean, because isset is used it doesn’t look at the index of the array however if array key exist is used it will output the data out correctly e.g.
I don’t know about the speed of this though, I think it would be slower so defeats the object really.
No. 11 — July 16th, 2007 at 11:26 am
Hi,
array_key_exists has the same drawback, it breaks the loop if there is a gap (because the condition get’s false) … it’s only an other function call.
so, “problem” (if the condition is that you want to have all contents of the array) is not solved.
btw: is there a way to know if my comment is submitted correctly?
No. 12 — July 16th, 2007 at 11:30 am
argh, my code was sucked up by the system! (i’ve used the code format option mentioned above) … so the code was:
/*
Output wanted:
1
2
3
4
6
Output you’ll get:
1
2
3
4
*/
No. 13 — July 16th, 2007 at 11:33 am
Robin it doesn’t break the loop, I’ve tested it. See for yourself.
Comments are in moderation before they are displayed to stop manual comment spam. At the moment the site doesn’t notify you if your comment is successful.
Automated comment spam is protected against using my plugin SpamBam and we don’t get any automated spam. But there is no way to prevent manual comment spam submissions.
No. 14 — July 16th, 2007 at 11:37 am
There is no break in your code because you have no “unset” … so you have a continously numerated array 😉
The condition is true for every check = it does not break in the middle of the array.
Another thing that comes to my mind:
is === really fast as ==? Because it’s one check more, which must be slower in my opinion. But I’m not sure for this one.
No. 15 — July 16th, 2007 at 11:37 am
Sorry yes you’re correct, just retested. Sorry for the confusion but it is monday 🙂
No. 16 — July 16th, 2007 at 11:39 am
This does work as expected:-
No. 17 — July 16th, 2007 at 11:42 am
hmm, I have a typo in my comment, my other question is: “Is === really fastER than ==, because it does one more check which naturally means it’s slower.”
Again, not sure for this.
And: Is there a way to edit comments? I’m at work and it’s monday … that’s the ideal situation for making many typos 😉
No. 18 — July 16th, 2007 at 11:43 am
I might do a comprehensive benchmark test on the various functions etc but I was hoping that someone knew a site that had already done one so I can link to it in this post.
No. 19 — July 16th, 2007 at 11:47 am
I’ve added a benchmark link to the post now.
No. 20 — July 16th, 2007 at 11:50 am
Robin you should have an option to edit posts when you login, if not I shall have a look at the wordpress configuration.
No. 21 — July 16th, 2007 at 11:53 am
Thank you for the benchmark link, I will digg deeper into this == vs. === thing.
And no, I have no option to edit a post or I am blind. I’m already logged in, in fact I must, because you aren’t allowed to write anonymous comments here 😉
No. 22 — July 16th, 2007 at 11:57 am
If you find out more information I would be grateful if you can keep me informed, I could add it to the post and credit you with a site link.
I shall look into the configuration because you should be able to edit your comments.
No. 23 — July 16th, 2007 at 12:26 pm
I’ve just added a few more benchmark links which I hope everyone finds useful.
No. 24 — July 16th, 2007 at 1:35 pm
@Robin: you’re right, the code won’t work with any array but so could be the case with the other 2 (slower) methods. Since you’re testing just for $i<count($array), there’s no guarantee that $array[$i] exists.
But in the situations where $array has consecutive values and no gaps the 3rd method is the fastest.
@Gareth: in my first post there are some semicolons after < comparisions – they should be removed.
$array[4]=null is not the same with unset($array[4]);
I don’t think your array_key_exists() method would work in that case.
Try your code with
$array = array(1=>1,2=>2,3=>3,5=>5,6=>6);
The better comparision would be for ($i=0;$i<count($array) && isset($array[$i]);++$i)
Of course count() should be pre-read first.
But the problem with this method is that if there are big gaps in the array it will loop through them for no reason. In this case you should use foreach()
No. 25 — July 16th, 2007 at 2:07 pm
Updated your comment with the corrected code. I don’t know why wordpress doesn’t allow people to edit their own comments. I hope to sort this out soon.
No. 26 — July 18th, 2007 at 6:49 pm
What are your thoughts on premature optimization? IMO, most of these comments that have been posted *may* give you a few microseconds on each call, at most a few milliseconds. I would assume that if you spent the same amount of time attempting to optimize your slowest SQL call, you will get orders of magnitude better returns than worrying about whether or not you are concatinating or using a comma in your echo statements.
No. 27 — July 18th, 2007 at 9:49 pm
Yes obviously optimising your SQL statements would but this page was simply to point out ways to increase performance however slight.
If you would care to share some tips then please do. I might add SQL tips at a later stage.
No. 28 — July 18th, 2007 at 11:38 pm
dancaragea, about that
I found it is not as fast as
My test are from this code, on PHP5.2:
Also, in some cases, the array can be looped backwards. like this
which is the fastest because compare to loop forward, one less conditional saved from every iteration.
No. 29 — July 20th, 2007 at 7:50 am
Hi,
it’s me again. Don’t had the time for know to test the difference between “==” and “===” but for now I believe the benchmark (even if really GOOD benchmarks are seldom, because most of them missing important points)
@Logan:
Yes, that’s clear. I think this post is intended to show everyone some small optimizations in the script language itselfs, nothing more.
It should be clear to everyone, that the real bottlenecks are elsewhere, so you can keep some simple rules:
1. use external resources wisely
2. do not code / use bloated code. Small code = fast code (in most cases ;))
3. include only the files that you really need
4. C code is faster than PHP code, so if you can solve the problem with an internal PHP function, do it!
and the most important rule:
5. Cache as much as possible!
alone the fifth point make way more sense than most of the code optimizations you can do … and it keeps your code read able.
SQL optimization is a good point to. If you work with MySQL I recommend you the book: “High performance MySQL” from Jeremy D. Zawodny
No. 30 — July 20th, 2007 at 7:53 am
Oh, and one other thing:
Try Memcache for caching and xdebug for profiling, they both do their job very well.
(I’m sorry for the typos in my previous post … switching between languages in the early morning ;-))
No. 31 — July 29th, 2007 at 5:31 am
@Mgccl:
for ($i=count($some_array);$i;){
–$i;
}
Is that the best way to this? Wouldn’t it be better to use a temporary variable instead of asking the for loop to count the array each time? It was mentioned earlier in the comments, but not-seeing it here makes me wonder if it was intentional, or just intending to show the decrement.
$temp = count($some_array);
for ($i=count($temp);$i;){
–$i;
}
No. 32 — July 29th, 2007 at 5:32 am
Uh, when copy/pasting the above, I forgot to remove the count() from the for loop, DUH.
I’m not posting on a Monday morning; I’m posting at 12:30 on a Saturday night and blame the goof on the fact that I’m looking up PHP optimizations on a Saturday night 😛
No. 33 — August 23rd, 2007 at 2:56 pm
I’m no expert on this, but here’s my understanding:
Regarding == vs ===, the identity check (===) actually will be doing less processing because it doesn’t have to cast variables to different types.
I did some benchmarking:
5,000,000 iterations
TESTS:
1.1: 1 == 1
1.2: 1 == ‘1’
1.3: 1 == 2
1.4: 1 == ‘a’
2.1: 1 === 1
2.2: 1 === ‘1’
2.3: 1 === 2
2.4: 1 === ‘a’
RESULTS:
1.1: 4.2496 (108.0435%)
1.2: 5.4232 (137.8819%)
1.3: 4.8647 (123.6827%)
1.4: 5.3762 (136.6878%)
2.1: 4.0064 (101.8609%)
2.2: 3.9332 (100%)
2.3: 3.9355 (100.059%)
2.4: 3.9373 (100.1045%)
so you can see that identity checking is much quicker.
No. 34 — September 18th, 2007 at 3:51 pm
I recently was having a performance problem iterating through a class in php 5 using $this to access a variable.
I tried creating a reference to the variable ie
$var = & $this->var;
The speed tests were impressive.
At 1,000,000 iterations
This()
Start Time:1188316233.75
End Time:1188316234.3781
Total Time:0.62805891036987
Ref()
Start Time:1188316234.3781
End Time:1188316234.5309
Total Time:0.15274381637573
No. 35 — October 6th, 2007 at 4:04 pm
Another article about optimizing the performance of apache & php for high traffic loads:
http://kevin.vanzonneveld.net/techblog/article/survive_heavy_traffic_with_your_webserver
No. 36 — December 11th, 2008 at 8:54 pm
A couple other performance saving tips:
Use single quotes instead of double quotes if you have no variables in the string. When single quotes are used, PHP doesn’t bother to search the string for any variables.
require_once() is more expensive than require().
No. 37 — October 9th, 2010 at 9:33 am
Use double quote string is best practice in PHP: http://www.linuxask.com/questions/should-i-always-use-single-quotes-for-php-strings