11. Caching

PHP is pretty quick by itself, but bottlenecks can arise when you make remote connections, load files, etc. Thankfully, there are various tools available to speed up certain parts of your application, or reduce the number of times these various time-consuming tasks need to run.

11.1 Object Caching

There are times when it can be beneficial to cache individual objects in your code, such as with data that is expensive to get or database calls where the result is unlikely to change. You can use object caching software to hold these pieces of data in memory for extremely fast access later on. If you save these items to a data store after you retrieve them, then pull them directly from the cache for following requests, you can gain a significant improvement in performance as well as reduce the load on your database servers.

Many of the popular bytecode caching solutions let you cache custom data as well, so there’s even more reason to take advantage of them. APCu and WinCache both provide APIs to save data from your PHP code to their memory cache.

The most commonly used memory object caching systems are APCu and memcached. APCu is an excellent choice for object caching, it includes a simple API for adding your own data to its memory cache and is very easy to setup and use. The one real limitation of APCu is that it is tied to the server it’s installed on. Memcached on the other hand is installed as a separate service and can be accessed across the network, meaning that you can store objects in a hyper-fast data store in a central location and many different systems can pull from it.

Note that whether the cache is shared across PHP processes depends on how PHP is used. When running PHP via PHP-FPM, the cache is shared across all processes of all pools. When running PHP as a (Fast-)CGI application inside your webserver, the cache is not shared, i.e every PHP process will have its own APCu data. When running PHP on the command line, the cache is not shared and will only exist for the duration of the command, so you have to be mindful of your situation and goals. You might want to consider using memcached instead, as it’s not tied to the PHP processes.

In a networked configuration APCu will usually outperform memcached in terms of access speed, but memcached will be able to scale up faster and further. If you do not expect to have multiple servers running your application, or do not need the extra features that memcached offers then APCu is probably your best choice for object caching.

Example logic using APCu:

1 <?php
2 // check if there is data saved as 'expensive_data' in cache
3 $data = apcu_fetch('expensive_data');
4 if ($data === false) {
5     // data is not in cache; save result of expensive call for later use
6     apcu_add('expensive_data', $data = get_expensive_data());
7 }
8 
9 print_r($data);

11.2 Opcode Cache

When a PHP file is executed, it must first be compiled into opcodes (machine language instructions for the CPU). If the source code is unchanged, the opcodes will be the same, so this compilation step becomes a waste of CPU resources.

An opcode cache prevents redundant compilation by storing opcodes in memory and reusing them on successive calls. It will typically check signature or modification time of the file first, in case there have been any changes.

It’s likely an opcode cache will make a significant speed improvement to your application. Since PHP 5.5 there is one built in - Zend OPcache. Depending on your PHP package/distribution, it’s usually turned on by default - check opcache.enable and the output of phpinfo() to make sure. For earlier versions there’s a PECL extension.

Read more about opcode caches:

11.3 Virtual or Dedicated Servers

If you are comfortable with systems administration, or are interested in learning it, virtual or dedicated servers give you complete control of your application’s production environment.

nginx and PHP-FPM

PHP, via PHP’s built-in FastCGI Process Manager (FPM), pairs really nicely with nginx, which is a lightweight, high-performance web server. It uses less memory than Apache and can better handle more concurrent requests. This is especially important on virtual servers that don’t have much memory to spare.

Apache and PHP

PHP and Apache have a long history together. Apache is wildly configurable and has many available modules to extend functionality. It is a popular choice for shared servers and an easy setup for PHP frameworks and open source apps like WordPress. Unfortunately, Apache uses more resources than nginx by default and cannot handle as many visitors at the same time.

Apache has several possible configurations for running PHP. The most common and easiest to setup is the prefork MPM with mod_php. While it isn’t the most memory efficient, it is the simplest to get working and to use. This is probably the best choice if you don’t want to dig too deeply into the server administration aspects. Note that if you use mod_php you MUST use the prefork MPM.

Alternatively, if you want to squeeze more performance and stability out of Apache then you can take advantage of the same FPM system as nginx and run the worker MPM or event MPM with mod_fastcgi or mod_fcgid. This configuration will be significantly more memory efficient and much faster but it is more work to set up.

If you are running Apache 2.4 or later, you can use mod_proxy_fcgi to get great performance that is easy to setup.

11.4 Shared Servers

PHP has shared servers to thank for its popularity. It is hard to find a host without PHP installed, but be sure it’s the latest version. Shared servers allow you and other developers to deploy websites to a single machine. The upside to this is that it has become a cheap commodity. The downside is that you never know what kind of a ruckus your neighboring tenants are going to create; loading down the server or opening up security holes are the main concerns. If your project’s budget can afford to avoid shared servers, you should.

Make sure your shared servers are offering the latest versions of PHP.