Improving PHP performance

by Carl. 3 Comments

PHPUse of CMS in now widely spread and we do not need to dig into low level coding to write web pages any more. This said, we still some times have to be able to tweak performance when it comes to some specific developments. With attention to minor details, performance of PHP scripts can be optimized and help to match Google’s attention to speed. Numerous articles deal with improving performance of PHP scripts, here is a collection of some easy to implement tweaks.

  • Avoid needless copying variables. Sometimes, developers think they can make the code “cleaner” by copying predefined variables to variables with shorter names before working with them. This sounds like a good idea, but if the variable is altered in any way, the memory consumption is doubled, resulting in the slowdown of scripts. If the variable is quite large, this could result in a lot of extra processing. Use the copy you already have whenever possible, even if it doesn’t look pretty (e.g., $_POST[‘somevariable’]). For example, a user inserts 1MB worth of characters into a text area field. This implementation would result in nearly 2MB of memory being used. Of course, less available memory leads to decreased performance for the user.
  • Avoid string concatenations in loops. When placed in a loop, string concatenation results in the creation of large numbers of temporary objects and unnecessary use of the garbage collector. Both consume memory and can dramatically slow down script execution.
  • Avoid passing function variables by reference. In most cases, functions only need to use the values passed by their parameters, without altering the values of such parameters. In such cases, you can safely pass those parameters by reference (for example function (&$parameter) rather than by value (function ($parameter)). By doing so, you’ll avoid memory-intensive copies and increase application performance.
  • Avoid function tests in loop conditionals. Function tests in loop conditionals decrease application performance. When you use a loop through an array, the function is called every time. Instead, do a count() beforehand, store the value in a variable, and use it for the test. This way, you can avoid needlessly firing the test function for each iteration.
  • Avoid using relative paths. For better performance, it is highly advised to try and minimize the use of relative paths for file inclusion. The general mechanism for relative path inclusion will search for default include paths, then continue with current directory, and so on. In such cases, a file search will take more time. However, if you need to use relative paths, the best practice is to declare the constant “WEB_ROOT” which defines the root and use it afterwards.
    Absolute path which is also known as full path will be better compared to a relative path for PHP. Relative path might cause problem for the include and require operation in PHP, whereas absolute path doesn’t. Also using absolute path eliminate the need for the server to resolve the path for you. Simply to say, do you know where the file is located when you just look at a relative path or is it faster if you know the full path?
    Normalizing a relative file path can be expensive; giving PHP the absolute path (or even “./file.inc”) avoids the extra step.
  • Avoid methods with object instantiation in loops. PHP is an object-oriented language and one of the fundamental object-oriented performance management principles is to avoid excessive object creation. This doesn’t mean that you should give up the benefits of object-oriented programming by not creating any objects, but you should be wary of object creation inside tight loops when executing performance-critical code.
    Object creation is an expensive operation and therefore, when possible, avoid creating temporary or intermediate objects.
  • Use echo instead of print(). Comparatively  echo will score over print. It’s around 12%-20% faster using echo compare to print when there is no $ symbol used in the printing string. And around 40-80% faster if there is a $ symbol used in a printing string! This really demonstrate the differences between the keyword $ symbol used in PHP.
  • Avoid using period for “echo” function. If you use periods, PHP has to concatenate the string before it outputs. If you use commas, it just outputs them in order with no extra processing. To concatenate between two strings/variables most of the developers might use dot to concatenate such as the one shown below :

    $a = 'PHP programming ';
    $b = 'Improvement Tips';
    echo $a.$b;

    Instead of this,

    $a = 'PHP programming ';
    $b = 'Improvement Tips';
    echo $a,$b;

    Between these two which is more efficient? There are some bench marking test have been performed for dot and commas. The result shows that dot is more preferable if there are no variables or $ symbol involved in the operation which is around 200% faster. On the other hand, commas will help to increase around 20%-35% efficiency when dealing with $ symbols. So let us keep this information in mind while constructing the code and use them appropriately.

  • Avoid using regular expressions. Regular expressions are very useful, but also very time-consuming. Regular expressions are known to be much slower than their PHP counterparts. For example, use str_replace instead of preg_replace. For this reason, limiting their use is highly recommended.
  • Avoid using double quotes for long strings without variables. For strings declared using double quotes, PHP does extra processing to find potential variables which could be used inside those strings. Therefore, concatenation with single quotes is marginally faster.
    For example

    echo 'This is long string'.$name

    is faster than

    echo "This is long string $name"

    Combining variable concatenation with single quotes is faster than using double quotes with variables inside the declared string, because no extra string manipulation is needed. If you aren’t using variables in your string, it’s still recommended that you use single quotes. Otherwise, if possible, still use single quoted strings with variables concatenations.

  • Drop braces wherever applicable. If the condition is constrained to a single line, below code segment is better than the one following it with braces.

    if ($n > 10) $n --;
    else $n ++;

    Instead of this,

    if ($n > 10)
    {
    $n --;
    }
    else
    {
    $n ++;
    }

  • Optimize the loop. There are many ways we can define a loop in PHP. We have “for loop”, “foreach loop” and “while loop”. Using a “for loop” is better than “foreach” and “while” loops if the maximum loop is pre-calculated outside the “for loop”! What does it mean?
    Basically is this.
    Worst than foreach and while loop

    for($m =0; $m < count($array);$m++){
    echo 'This is bad practice, as the counting of array size within the loop.';
    }

    Better than foreach and while loop

    $total = (int)count($array);
    for($n =0; $n < $total;$n++){
    echo 'This is great, as we are counting the array size outside the loop.’;
    }

    The above code snippet shows two different ways of writing a “for loop”. The first way includes the operation count into the loop while the second one pre-calculate the total number of loop outside it. The difference between these two is that the second doesn’t run count operation n times while the first one did.

  • Use isset() instead of strlen(). This is actually a neat trick. Here is the example to check whether the string has more than 5 characters long:

    if (isset($username[5])) {
    // The username is at least six characters long.
    }

    In PHP strings are treated as arrays, each character in the string is an element within the array. By determining whether a particular element exists, you can determine whether the string is at least that many characters long. (Note that the first character is element 0, so $username[5] is the sixth character in $username.)
    The reason this is slightly faster than strlen() is complicated. The simple explanation is that strlen() is a function, and isset() is a language construct. Generally speaking, calling a function is more expensive than using a language construct.

  • explode() versus preg_split(). When you want to split a string you might have used explode because it supports even PHP4.0. The function preg_split() supports regular expressions. Anything that have regular expression support will usually be a bit more slower than those that doesn’t support it. It took around 20% faster using explode in PHP.
  • Memcached. Disk access is slow. Network access is slow. Databases typically use both. Memory is fast. Using a local cache avoids the overhead of network and disk access. Combine these truths and you get memcached. If your application isn’t distributed across multiple servers, you probably don’t need memcached. Simpler caching approaches — serializing data and storing it in a temporary file, for example — can eliminate a lot of redundant work on each request. In fact, this is the sort of low-hanging fruit we consider when helping our clients tune their apps. One of the easiest and most universal ways to cache data in memory is to use the shared memory helpers in Alternative PHP Cache (APC).
    Consider the following example:

    $stk_feed = apc_fetch('stocks');
    if ($stk_feed === FALSE) {
    $stk_feed = file_get_contents('http://example.org/stocks.xml');
    // Store this data in shared memory for ten minutes.
    apc_store('stocks', $stk_feed, 600);
    }
    // Do something with $stk_feed.

    Using the type of caching mentioned above, you don’t have to wait on a response from  remote server to send the feed data for every request. Some latency is incurred up to ten minutes in this example but can be adjusted to as close to real time as your application requires.

  • Avoid function tests in loop conditionals. If you’re looping through an array, for example, count() it beforehand, store the value in a variable, and use that for your test. This way, you avoid needlessly firing the test function with every loop iteration.
  • Use include() and require() instead of include_once() and require_once(). The structure include_once includes and checks the specified file during the script execution. The functionality is similar to include, but in the case of include_once, verification is done to check that the file has been included only once. For this reason, include_once is more costly than include statement. Sometimes it’s necessary, but you should default to include() in most situations.
  • Favor built-in functions over custom functions. Since PHP has to take the extra step of interpreting your custom functions, built-in functions have a performance advantage. More importantly, there are a lot of useful built-in functions that you may never learn about if you always default to writing your own.
  • Pass unchanged variables to a function by reference rather than value. This goes hand-in-hand with the point about needlessly copying variables. Much of the time, your functions only need to use the values from their parameters without changing them. In such cases, you can safely pass those parameters by reference (e.g., function(&$parameter) rather than function($parameter)) and avoid having to make memory-intensive copies.
  • Debug with error_reporting(E_ALL). Every warning is a performance improvement waiting to happen, but only if you can see it. Cleaning up warnings and errors beforehand can also keep you from using @ error suppression, which is expensive. Just don’t forget to turn off error reporting when you’re done; warnings and errors are expensive as well.
  • Use the error suppression operator correctly. Always try to avoid using the error suppression operator as the @ operator is rather slow and can be costly if you need to write code with performance in mind. Generally speaking, error suppression is slow. This is because PHP dynamically changes error_reporting to 0 before executing the suppressed statement, then immediately changes it back. This is time consuming. Worse, using the error suppression operator makes it difficult to track down the root cause of a problem.

This post is a mashup of several sources:

3 Responses to Improving PHP performance

  1. CoR says:

    You said “Avoid string concatenations in loops.”
    I have one function that does exactly the opposite. And it is slow. Very slow.
    So, how do you avoid for(){ .= } ? How to concatenate strings in loop?

    I have tried using array push and array[]= ‘str’. But for some odd reason, execution times were the same.

    Echo is my last untested option.

  2. olivedev says:

    You can also improve your PHP website’s performance by configuring Nginx web server along Apache and Varnish caching as well. You have already suggested using Memcached in your article, but using these packages will further improve the performance. I have been using this as a stack on my PHP website which hosting on AWS through Cloudways platform (https://www.cloudways.com/en/php-cloud-hosting.php ). I am also using Cloudflare CDN and PHP-FPM as well.

  3. Matt H says:

    I found your post today, and many of the tips are good. However, I thought “favor built-in functions” and “use include() … instead of include_once()” were contradictory, so I decided to setup a test to see which is faster.

    You can find the PHP code here (with test results at the bottom): http://pastebin.com/6G7772Z6

    My test were using PHP 5.6.4 (CLI):

    In summary, I found that include_once() is always faster by roughly 3x to 16x, depending on the include file size. The larger the file, the better include_once is. Even a completely empty include file saw 3x the performance with include_once().

    So go with your golden rule. “Favor built-in functions”

Leave a Reply

Your email address will not be published. Required fields are marked *