PHP - - By Fredric Mitchell

Easy Wins For More Performant PHP

Introduction

Making your website more performant can require a lot of layers. From setting up a reverse-proxy cache with Varnish to configuring a group of load balancers, there are many well-documented options.

What if you're just starting out? What if you have a smaller application? Are there things you can do now that will make difference?

This article will explore easy wins for more performant PHP you can implement either as standard practices for your development team or principles you can retrofit for an existing application.

At Minimum, Upgrade to PHP 5.4

As of this article, the latest version of PHP is currently 5.5.5. If you have the appropriate control over your server environment, you should consider using this version. While 5.5 introduces a lot of new concepts, the security updates it provides should be something to seriously consider.

If PHP 5.5.5 isn't an option, you MUST minimally begin with PHP 5.4. PHP 5.3 is not only almost 4 years old, it is slower and uses more memory than PHP 5.4.

Running Drupal? 7% faster on PHP 5.4 while using almost 50% less memory.

Autoload

Autoloading involves including classes in files that are used throughout your application without having to manually reference the file paths. Better performance is achieved by only loading the files when the classes are instantiated.

We can use Composer to achieve this result.

Composer has been covered in past articles for dependency management. For autoloading, you can simply add the location of the classes in your composer.json file. The only configuration option is the file mapping mechanism dictated by key in the JSON array.

For example, if you have classes in a src folder in PSR-0 format:

{
    "autoload": {
        "psr-0": { "": "src/" }
    }
}

If you had classes spread throughout a resources and library folder, the format is a little different:

{
    "autoload": {
        "classmap": ["resources/", "library/", "Something.php"]
    }
}

Be aware, however, that while this reduces the need to use require or include_once, performance may suffer if attempting to load a large number of files.

You can, however, mitigate this if you use an accelerator or opcode cache.

An alternative autoloader to also explore is the Symfony2 Classloader component, a technique covered in an earlier article.

Reduce Memory Usage in Code

There are certain techniques when using operators, loops, or variable assignment that use less memory and can possibly make your entire application more performant.

If appropriate, make object properties public to avoid unnecessary methods as this uses less memory in execution:

class A {
    public $foo;
    public function setFoo($bar) { $this->foo = $bar; }
    public function getFoo() { return $this->foo; }
}

$bat = new A();

// Slower
$bat->setFoo('baz');
$baz = $bat->getFoo();

// Faster
$bat->foo = 'baz';
$baz = $bat->foo;

Define the size of loops before iteration:

// Slower
for ($i = 0; $i < count($j); $i++)

// Faster
$count = count($j);
for ($i = 0; $i < $count; $i++)

Use the language construct isset() before any operation:

// Check for existence and type of variable
if (isset($foo) && is_array($foo)) { return $bar; }

Edit: The usage of isset() has been edited to correct an incorrect recommendation. The previous code sample was based off of my misunderstanding of a benchmark on  http://phpbench.com.

These techniques are a partial listing of recommendations by Google and documented with benchmarks. They obviously depend on the size of your data values and the complexity of your code, but instituting good habits at the beginning yield less headaches in the future.

Profile

Objective measurements of how well your masterpiece runs provides valuable insight and reduces subjective distractions. Profiling your code is very easy, but does require compiling an extension in your PHP runtime.

You can use the XDebug extension or the Advanced PHP Debugger (APD) extension to profile your code. Simply update your php.ini or add an INI file for your extension with the appropriate configuration options:

An example XDebug ini configuration for OSX w/ brew:

[xdebug]
zend_extension="/usr/local/Cellar/php54-xdebug/2.2.3/xdebug.so"   
xdebug.profiler_enable=1   
xdebug.profiler_output_dir="/tmp"

Learn about what functions or processes take the most time and adjust accordingly.

For a more robust profiling and monitoring experience, you can also consider installing tools from AppDynamics which, when installed as a server daemon and PHP extension, allow for in-depth analysis of your complex and large applications. This is a great option for optimizing legacy code.

OpCode Caching

Last, but not least, is the tried and true favorite of executing code from memory. This is performant because it reduces the need to read the code from disk and compile it.

As of PHP 5.5 (another reason to update), OpCache, an open-source caching project from Zend, is included by default.

For earlier versions, you simply need to install ZendOpCache via PECL.

An example ZendOpCache ini configuration on OSX w/ brew:

[opcache]
zend_extension="/usr/local/Cellar/php54-opcache/7.0.2/opcache.so"   
zend_optimizerplus.memory_consumption=128   
zend_optimizerplus.interned_strings_buffer=8   
zend_optimizerplus.max_accelerated_files=4000   
zend_optimizerplus.revalidate_freq=60   
zend_optimizerplus.fast_shutdown=1   
zend_optimizerplus.enable_cli=1   
zend_optimizerplus.enable_file_override=1   
apc.cache_by_default = false

Summary

Hopefully the above techniques give you a starting point for making your PHP applications faster. Whether you're refactoring your code to be more compatible with PHP 5.5 or simply making your loops use less memory, there are many easy wins that you can implement right now. Don't wait!


This is a sponsored article. The company that sponsored it compensated SitePoint to write and publish it. Independently written by SitePoint, sponsored articles allow us to develop and present content that’s most useful and relevant to our readers.
Sponsors