Sunday, September 7, 2008

PHP Tips and Tricks

If a method can be static, declare it static. Speed improvement is by a factor of 4.

echo is faster than print.

Use echo's multiple parameters instead of string concatenation.

Set the maxvalue for your for-loops before and not in the loop.

Unset your variables to free memory, especially large arrays.

Avoid magic like __get, __set, __autoload and require_once() is expensive

Use full paths in includes and requires, less time spent on resolving the OS paths.

If you need to find out the time when the script started executing, $_SERVER[’REQUEST_TIME’] is preferred to time()

See if you can use strncasecmp, strpbrk and stripos instead of regex

str_replace is faster than preg_replace, but strtr is faster than str_replace by a factor of 4

If the function, such as string replacement function, accepts both arrays and single characters as arguments, and if your argument list is not too long, consider writing a few redundant replacement statements, passing one character at a time, instead of one line of code that accepts arrays as search and replace arguments.

It's better to use select statements than multi if, else if, statements.

Error suppression with @ is very slow.

Turn on apache's mod_deflate

Close your database connections when you're done with them

$row[’id’] is 7 times faster than $row[id]

Error messages are expensive

Do not use functions inside of for loop, such as for ($x=0; $x <>

Incrementing a local variable in a method is the fastest. Nearly the same as calling a local variable in a function.

Incrementing a global variable is 2 times slow than a local var.

Incrementing an object property (eg. $this->prop++) is 3 times slower than a local variable.

Incrementing an undefined local variable is 9-10 times slower than a pre-initialized one.

Just declaring a global variable without using it in a function also slows things down (by about the same amount as incrementing a local var). PHP probably does a check to see if the global exists.

Method invocation appears to be independent of the number of methods defined in the class because I added 10 more methods to the test class (before and after the test method) with no change in performance.

Methods in derived classes run faster than ones defined in the base class.

A function call with one parameter and an empty function body takes about the same time as doing 7-8 $localvar++ operations. A similar method call is of course about 15 $localvar++ operations.

Surrounding your string by ' instead of " will make things interpret a little faster since php looks for variables inside "..." but not inside '...'. Of course you can only do this when you don't need to have variables in the string.

When echoing strings it's faster to separate them by comma instead of dot. Note: This only works with echo, which is a function that can take several strings as arguments.

A PHP script will be served at least 2-10 times slower than a static HTML page by Apache. Try to use more static HTML pages and fewer scripts.

Your PHP scripts are recompiled every time unless the scripts are cached. Install a PHP caching product to typically increase performance by 25-100% by removing compile times.

Cache as much as possible. Use memcached - memcached is a high-performance memory object caching system intended to speed up dynamic web applications by alleviating database load. OP code caches are useful so that your script does not have to be compiled on every request

When working with strings and you need to check that the string is either of a certain length you'd understandably would want to use the strlen() function. This function is pretty quick since it's operation does not perform any calculation but merely return the already known length of a string available in the zval structure (internal C struct used to store variables in PHP). However because strlen() is a function it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. In some instance you can improve the speed of your code by using an isset() trick.
Ex.
if (strlen($foo) < 5) { echo "Foo is too short"; }
vs.
if (!isset($foo{5})) { echo "Foo is too short"; }
Calling isset() happens to be faster then strlen() because unlike strlen(), isset() is a language construct and not a function meaning that it's execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string's length.

When incrementing or decrementing the value of the variable $i++ happens to be a tad slower then ++$i. This is something PHP specific and does not apply to other languages, so don't go modifying your C or Java code thinking it'll suddenly become faster, it won't. ++$i happens to be faster in PHP because instead of 4 opcodes used for $i++ you only need 3. Post incrementation actually causes in the creation of a temporary var that is then incremented. While pre-incrementation increases the original value directly. This is one of the optimization that opcode optimized like Zend's PHP optimizer. It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization and there are plenty of ISPs and servers running without an opcode optimizer.

Not everything has to be OOP, often it is too much overhead, each method and object call consumes a lot of memory.

Do not implement every data structure as a class, arrays are useful, too

Don't split methods too much, think, which code you will really re-use

You can always split the code of a method later, when needed

Make use of the countless predefined functions

If you have very time consuming functions in your code, consider writing them as C extensions

Profile your code. A profiler shows you, which parts of your code consumes how many time. The Xdebug debugger already contains a profiler. Profiling shows you the bottlenecks in overview

mod_gzip which is available as an Apache module compresses your data on the fly and can reduce the data to transfer up to 80%

  1. The more you understand the software you are using (Apache, PHP, IIS, your database) and the deeper your knowledge of the operating system, networking and server hardware, the better you can perform global optimizations on your code and your system.
  2. For PHP scripts, the most expensive bottleneck is normally the CPU. Twin CPUs are probably more useful than two Gigabytes of RAM.
  3. Compile PHP with the "configure –-enable-inline-optimization" option to generate the fastest possible PHP executable.
  4. Tune your database and index the fields that are commonly used in your SQL WHERE criteria. ADOdb, the very popular database abstraction library, provides a SQL tuning mode, where you can view your invalid, expensive and suspicious SQL, their execution plans and in which PHP script the SQL was executed.
  5. Use HTML caching if you have data that rarely changes. Even if the data changes every minute, caching can help provided the data is synchronized with the cache. Depending on your code complexity, it can improve your performance by a factor of 10.
  6. Benchmark your most complex code early (or at least a prototype), so you get a feel of the expected performance before it is too late to fix. Try to use realistic amounts of test data to ensure that it scales properly.

Updated 11 July 2004: To benchmark with an execution profile of all function calls, you can try the xdebug extension. For a brief tutorial of how i use xdebug, see squeezing code with xdebug. There are commercial products to do this also, eg. Zend Studio.

  1. Consider using a opcode cache. This gives a speedup of between 10-200%, depending on the complexity of your code. Make sure you do some stress tests before you install a cache because some are more reliable than others.
  2. Use ob_start() at the beginning of your code. This gives you a 5-15% boost in speed for free on Apache. You can also use gzip compression for extra fast downloads (this requires spare CPU cycles).
  3. Consider installing Zend Optimizer. This is free and does some optimizations, but be warned that some scripts actually slow down when Zend Optimizer is installed. The consensus is that Zend Optimizer is good when your code has lots of loops. Today many opcode accelerators have similar features (added this sentence 21 Oct 2003).
  4. Optimize your loops first. Move loop invariants (constants) outside the loop.
  5. Use the array and string functions where possible. They are faster than writing equivalent code in PHP.
  6. The fastest way to concatenate multiple small strings into one large string is to create an output buffer (ob_start) and to echo into the buffer. At the end get the contents using ob_get_contents. This works because memory allocation is normally the killer in string concatenation, and output buffering allocates a large 40K initial buffer that grows in 10K chunks. Added 22 June 2004.
  7. Pass objects and arrays using references in functions. Return objects and arrays as references where possible also. If this is a short script, and code maintenance is not an issue, you can consider using global variables to hold the objects or arrays.
  8. If you have many PHP scripts that use session variables, consider recompiling PHP using the shared memory module for sessions, or use a RAM Disk. Enable this with "configure -–with-mm" then re-compile PHP, and set session.save_handler=mm in php.ini.
  9. For searching for substrings, the fastest code is using strpos(), followed by preg_match() and lastly ereg(). Similarly, str_replace() is faster than preg_replace(), which is faster than ereg_replace().
  10. Added 11 July 2004: Order large switch statements with most frequently occuring cases on top. If some of the most common cases are in the default section, consider explicitly defining these cases at the top of the switch statement.
  11. For processing XML, parsing with regular expressions is significantly faster than using DOM or SAX.
  12. Unset() variables that are not used anymore to reduce memory usage. This is mostly useful for resources and large arrays.
  13. For classes with deep hierarchies, functions defined in derived classes (child classes) are invoked faster than those defined in base class (parent class). Consider replicating the most frequently used code in the base class in the derived classes too.
  14. Consider writing your code as a PHP extension or a Java class or a COM object if your need that extra bit of speed. Be careful of the overhead of marshalling data between COM and Java.

Useless Optimizations

Some optimizations are useful. Others are a waste of time - sometimes the improvement is neglible, and sometimes the PHP internals change, rendering the tweak obsolete.

Here are some common PHP legends:

a. echo is faster than print

Echo is supposed to be faster because it doesn't return a value while print does. From my benchmarks with PHP 4.3, the difference is neglible. And under some situations, print is faster than echo (when ob_start is enabled).

b. strip off comments to speed up code

If you use an opcode cache, comments are already ignored. This is a myth from PHP3 days, when each line of PHP was interpreted in run-time.

c. 'var='.$var is faster than "var=$var"

This used to be true in PHP 4.2 and earlier. This was fixed in PHP 4.3. Note (22 June 2004): apparently the 4.3 fix reduced the overhead, but not completely. However I find the performance difference to be negligible.

Do References Speed Your Code?

References do not provide any performance benefits for strings, integers and other basic data types. For example, consider the following code:

function TestRef(&$a)
{
    $b = $a;
    $c = $a;
}
$one = 1;
ProcessArrayRef($one);

And the same code without references:

function TestNoRef($a)
{
    $b = $a;
    $c = $a;
}
$one = 1;
ProcessArrayNoRef($one);

PHP does not actually create duplicate variables when "pass by value" is used, but uses high speed reference counting internally. So in TestRef(), $b and $c take longer to set because the references have to be tracked, while in TestNoRef(), $b and $c just point to the original value of $a, and the reference counter is incremented. So TestNoRef() will execute faster than TestRef().

In contrast, functions that accept array and object parameters have a performance advantage when references are used. This is because arrays and objects do not use reference counting, so multiple copies of an array or object are created if "pass by value" is used. So the following code:

function ObjRef(&$o)
{

$a =$o->name;
}

is faster than:

$function ObjRef($o)
{

$a = $o->name;
}

Note: In PHP 5, all objects are passed by reference automatically, without the need of an explicit & in the parameter list. PHP 5 object performance should be significantly faster.

2 comments:

Rajkumar said...

fine...
its very useful for me...

with regards
rajkumar

கேசவன் முத்துவேல் said...

Ok., but no well described structure in the post, I feel. More space is swallowed by theme itself. Changing this will attract more user as well as looks better.