PHP Performance Best Practices

A post on Savant-Talk got me thinking about performance issues with PHP. I believe that the key to making your PHP apps fast and scalable starts with good design practices. Here’s a checklist of what I do to keep my PHP apps running fast.

  • Avoid repeated function calls. Take this example:
    $data = '1234567890';
    for ($i = 1; $i < = strlen($data); $i++) {
        ...
    }
    

    This code will call strlen once for every iteration of the loop. If you call strlen once and store it’s result, your code will run faster.

  • Research built-in functions. PHP has tons of functions for solving common problems. For example:
    $foo = array(1, 2, ... n);
    $out = '';
    foreach ($foo as $v)  {
        $out .= $v;
    }
    $v = trim(',', $v);
    

    Can be restated as:

    $foo = array(1, 2, ... n);
    $out = implode(',', $n);
    
  • Use foreach(). The alternative syntax for looping through an array looks like this:
    while(list($k, $v) = each($array)) {
        ...
    }
    

    In addition to being less clear about what’s going on with the loop, list() and each() are called for each iteration.

  • Use array_keys() with foreach(). foreach() returns a copy of the array value. When dealing with arrays which have large amounts of data (e.g. objects or large arrays), use array_keys() to avoid excessive memory consumption.
    foreach(array_keys($array) as $ak) {
        $v =& $array[$ak];
        ...
    }
    
  • Use references for large arrays and objects. In PHP, $foo = $bar makes a copy of $bar, and stores it in $foo. PHP’s garbage collection sucks, so you end up with copies of stuff all over the place, wasting memory and CPU cycles. Use a reference instead: $foo =& $bar. This makes $foo point to $bar, instead of making a copy.
  • Avoid regexes in favor of str_replace() and strstr(). Don’t use regexes unless you realy need them. The string functions are much faster.
  • Avoid POSIX regexes altogether. If you do need to use a regex, use the PERL regex functions (preg_match(), preg_replace() etc) instead of the POSIX regex functions.
  • Use string concatenation instead of sprintf(). Unless you need the formatting capabilities of sprintf(), avoid it. Plain string concatenation is around twice as fast.
  • Use echo instead of print(). echo is a statement (like include, if etc), so you avoid the function overhead of print().
  • Avoid output buffering. Output buffering can be a great tool, but it increases memory overhead, and degrades the user experience of your webapps. If you output data when it’s ready, it streams to the user as your script executes, and the browser can begin displaying it immediately. With output buffering, the whole page is sent at once, making things appear slower to the user.
  • Profile your code! These practices work for me, but test with your code! Find out where the bottlenecks are, and fix the biggest ones first. PEAR::Benchmark is good for timing procedural elements of your code, and APD gives function call and execution time profiles, including for PHP’s built-in functions.
  • Use single quotes for strings. PHP parses strings which use double-quotes for variables, function calls and the like, whereas it simply outputs strings with single-quotes. Really, the performance benefit is not significant. I do not recommend that you start changing all your code to use single quotes - the chance that you will break something outweighs the tiny performance benefit you would regognize. But if you’re building something from the ground-up, use single-quotes.

13 Responses to “PHP Performance Best Practices”

  1. Bas van der Doorn Says:

    I have been optimizing the output speed of a large table that is dynamically generated out of a database. I have found that when creating an output string using .= and echoing that at the end of the script is much faster for broadband users with latency’s around 30-100 ms then echoing every small piece of the webpage (every TD in my case). All the echoes resulted in a display time of 8 seconds, while the .= strategy managed to do it in 6. This was measured by stopwatch several times to be sure, and is the time from clicking on the refresh button, till the appearance of the page. At the univeristy the server latency is lower than 1 ms and I do not notice any speed change here between old and new code. At home it is a big change though… hope this can help others!

  2. Richard Lynch Says:

    Single-quotes aren’t really any faster than double-quotes.

    That’s a myth.

    Note that single-quotes DO have two (2) special character combinations:
    \’ to embed a single-quote
    \\ to embed a \

    Though \ by itself “works” unless followed by ‘, you are probably thinking more clearly about what’s really happening inside the guts of the string if you use \\ when you want \

    At any rate, the low-level code for single-quote has to iterate through ’string’ and examine each character just as “string” does.

    There may be a TINY benefit in that it only has to consider a smaller set of ’special’ characters (\ and ‘), and only has two or three possible branches from finding that special character, instead of a half-dozen, and the branches are inherently simpler, but…

    It’s the ITERATION through each character that costs CPU time, really.

    So if you actually benchmark these, you’re not going to find much different between ” and “” for any real-world situation where both are appropriate.

  3. Ian Eure Says:

    “Single-quotes aren’t really any faster than double-quotes. That’s a myth.”
    No, it’s a myth that they are significantly faster, which I don’t claim.

    “So if you actually benchmark these, you’re not going to find much different between ‘’ and “” for any real-world situation where both are appropriate.”
    You’re right - there isn’t much difference, but single quotes are slightly faster. I ran some comparative tests a while back - I suppose the situation may have changed with PHP 4.4.0/5, but it was faster at the time.

    And why use double-quotes if you don’t need to parse variables in the string anyways? I see this as akin to using preg_match() or ereg() where a strstr() would work just as well. If you don’t need all the features something offers, why use something that offers them and is slower, even if only very slightly so?

    I do mention that you should profile your code. Anyone who tries to optimize without examining the impact will not get good results. None of this stuff is absolute; everything depends on your setup. Perhaps I should have stressed that more.

  4. TechnoPetr » Blog Archive » PHP Smorgasboard Says:

    [...] Atomized | PHP Performance Best Practices [...]

  5. LeoTech » Blog Archive » Javascript Smorgasboard Says:

    [...] In addition to the PHP Performance link from yesterday, I just added four related to Javascript to the sidebar. [...]

  6. Hans Duedal Says:

    My studies of “string concatenation instead of sprintf()” show a 20% performance increase in favor of string concatenation. Not 100% as you mentioned. I many cases I would prefer sprintf for the clarity the syntax provides when the speed increase is no more than in average 20%.
    This is testet on PHP 5.2.1 running in CLI mode on Ubuntu.

  7. Ian Eure Says:

    Hans,
    Thanks for the feedback. I ran these tests a while back, and have not re-run them with PHP 5. The situation with some of these items has changed; for example, PHP 5 supports foreach by reference, which PHP 4 did not. The variability of these factors is precisely why I implore people to test different scenarios to find the best balance for their use-case.

    You’re absolutely right that there is a trade-off of clarity vs. speed for string operations. It’s an individual choice as to whether it’s a win or not.

  8. TruePath Says:

    So long as you aren’t modifying the arrays passing by reference shouldn’t be any faster. It is my understanding (from a comment posted in the PHP manual on references) that internally php always passes/assigns by reference adding appropriate copy on write flags so data can masquerade as a copy.

    In any case it is far from clear that passing by reference results in better performance *unless* you want to modify the values in the array and have those changes show up in two places.

  9. kvz Says:

    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

  10. James Says:

    been looking around the web for a good article on performance tuning.

    I have a script that is approximately 30,000 lines long (it’s a simulator)… I’ve recently begun to hack out logical pieces of the script and place them in separate files… as the script will run, it will include whatever applicable file is needed at that time.

    I’ve read that having a massive number of includes can actually reduce performance due to file I/O delays.

    At what point do the delays from the includes start to outweigh the parse time of a single large script?

  11. Martin Rusev Blog about web development and graphic design » Blog Archive » PHP performance tips around the web Says:

    [...] http://atomized.org/2005/04/php-performance-best-practices/ [...]

  12. Ian Says:

    @James, If you have 30k LOC in one file, your concerns should be about the maintainability of your application, not performance.

    Taking a speed hit in exchange for maintainability gains is a good trade-off. CPU cycles are cheap and only getting cheaper. Developer cycles are expensive and getting more so.

  13. henrietta Says:

    “”In PHP, $foo = $bar makes a copy of $bar, and stores it in $foo.”"

    Yeah, but Zend Engine implements Copy-On-Write logic. As stated in a PHP documentation comment, in most cases the Zend Engine > you.

Leave a Reply