8 easy tips to speed up your PHP

I had never written a single line of PHP until I started my new gig last October. I’d like to think that I’ve quickly gotten the hang of working on a large PHP codebase, especially after spending some quality time on Stack Overflow and the PHP Benchmark. After a few months, I started spotting some pretty hairy patterns. I recently started taking on more of a performance-focused role and thought I’d share a few tips on some tiny, incremental low-hanging fruit.

Before diving in, however, I do want to point out one thing: premature optimisations are never a good idea, so please run some benchmarks before digging into a micro-optimization rabbit-hole.

Use idx() or isset() for array access.

If you’re used to writing if($args['key']), then it’s time to start replacing these checks with some handy built-in functions. Use isset to ensure that a value is set for your target key. If you’re checking hundreds of thousands of keys, timed tests show that isset() is slightly faster than array_key_exists() and you should opt for the former.

If your code is littered with $args['key'] ? true : false, then it’s time to start replacing these with idx($args, 'key', false). Not only is this more meaningful for other programmers who come across your code, it’s more efficient when you tell PHP exactly what it should be looking for.

Beware of excessive database access.

When you’re chaining a whole bunch of functions together, make sure you keep track of when and where you’re calling out to the database. Calling an innocent little helper function from within a loop might actually result in many, tiny, inefficient database calls. Whatever you do, ensure you’re batching requests and avoid death by a thousand paper cuts.

Loops are evil.

Beware of sneakily nested array operations.

$rows = array(
000001 => array( 'name' => 'Alice' ),
000002 => array( 'name' => 'Bob' ),
);
$targets = array(000005, 000004, 000001);
$intersection = array();
foreach($rows as $row){
if(in_array($row, $targets)) $intersection[$row['id']] = $row;
}

in_array looks innocent, but be warned! You’re looking at O(n) operations in that single little builtin function. If $rows is of length m, then we’re looking at a worst-case scenario of O(m•n). Remember that you have more in your arsenal than just in_array. If you cleverly manipulate your data structures, you’ll be able to do this whole operation in one clean swoop.

$rows = array(
000001 => array( 'name' => 'Alice' ),
000002 => array( 'name' => 'Bob' ),
);
$targets = array(000005, 000004, 000001);
$intersection = array();
foreach($rows as $row){
if($targets[$row['id']]) $intersection[$row['id']] = $row;
}

Now we’re down to O(m)! All that studying you might’ve done for those basic algorithms interviews comes in handy when you’re attempting to save a few seconds.

Strtr() over str_replace() over preg_replace()

If you’re doing some simple string manipulations, always opt for strtr(). strtr() performs best with straight character replacements. Longer strings give str_replace() the edge.

If you’re strictly doing a string operation, use str_replace(), but if you’re looking to do some pattern-matching, then you’ll hate to take the performance hit of preg_replace().

Know when to use a switch. Know when to use an if/else.

When doing a strict equality comparison, it might actually be more efficient to use if ... elseif ... than a switch. Why? The switch statement executes one statement at a time. PHP will continue to execute the statements until it reaches the end of the switch block, or it spots a break statement.

Single quotes vs double quotes.

Strings enclosed in single quotes are not intended to be evaluated, unlike those enclosed in double quotes. By wrapping a string in double quotes, the program spends time looking for variables that might not be there. Simply put, use single quotes unless you’re inserting variables.

Take advantage of asynchronous operations.

Not everything needs to be done right this second. If you don’t need to respond to a request right away, why not put it on a queue and execute it later? Invest the time and energy in creating a simple, reliable job queue system so you can run some tasks in the background and keep your app responsive to new requests.

Cache, cache, cache.

Did I say cache? PHP is great for dealing with stateless, individual requests. However, a stateless system doesn’t mean you won’t be referring to something over and over again. Why not prevent your code from making yet another call over the network to your database and keep the information as local as possible.

Want to map your improvements?

Run XPROF and simple memory usage metrics. It’s as easy as adding just a few more lines of code to your area of concern.

$time = microtime(TRUE);
$memory = memory_get_usage();
print_r(array(
'memory' => (memory_get_usage() - $memory) / (1024 * 1024),
'seconds' => microtime(TRUE) - $time,
));
Like what you read? Give Maude Lemaire a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.