Bytecode Caching

It was a conscious decision to make the compilation of PHP source code into PHP bytecode for execution an implicit operation. A PHP developer does not need to think about compilation while he or she is “getting things done”. This implicit compilation step is the reason for the rapid feedback loop PHP developers are so used to. Traditionally, this allowed the developer to alternate between editing the source code and refreshing a page in the browser. Modern best practices like test-driven development replace the browser with executing automated tests.

This rapid feedback loop during development, however, comes with a price that has to be paid in production: PHP source code has to be compiled into PHP bytecode for each request. This is an expensive process that costs time and memory. Moreover, recompiling the same source code over and over again is superfluous. This is where bytecode caching comes into play. A bytecode cache stores the compiled representation of PHP source code and can significantly increase the performance (up to 70% more requests per second).

Implicit compilation combined with bytecode caching gives PHP developers the best of both worlds: quick feedback to frequent code changes during development and fast execution in production.

Since version 4, the PHP interpreter can be extended with bytecode caching capabilities. Over the years, various open source and closed source solutions were made available. PHP 5.5 was the first version of PHP to ship with an out-of-the-box bytecode cache. It is based on the once commercial product ZendOptimizer+, is called OpCache, and shows significant performance improvements over APC (between 5% and 20% more requests per seconds). APC, or Alternative PHP Cache, was the de-facto standard, open source solution for bytecode caching before PHP 5.5 and is no longer maintained.

When you download PHP 7 from https://php.net and build the PHP interpreter yourself, the opcache extension is built – but disabled – by default. If you do not build PHP yourself and instead use a package provided by the vendor of your Linux distribution to manage your PHP environment then, depending on your Linux distribution, you might need to install a separate package to get the opcache extension.

Before PHP 7, OpCache was only able to store PHP bytecode in shared memory. This is exactly where you typically want to store the bytecode of your web application. OpCache can optionally store PHP bytecode in the filesystem as of PHP 7. This makes bytecode caching finally available for PHP code that is executed on the command-line. This can, for instance, reduce the execution time of a test suite.

Here is how to set up bytecode caching using OpCache in the PHP CLI interpreter’s php.ini configuration file:

opcache.enable_cli=1
opcache.file_cache=/tmp
opcache.file_cache_only=1

With opcache.enable_cli=1 we enable bytecode caching for the PHP CLI interpreter. Using the opcache.file_cache directive we configure the path to a directory in which the cached bytecode will be stored. This directory must exist and should be on a RAM disk (mounted using tmpfs, for instance). The opcache.file_cache_only directive configures OpCache to exclusively utilize the filesystem-backed cache. This bypasses the shared memory storage which is useless on the command-line.

The filesystem-backed cache may also be useful for deploying the compiled bytecode representation of PHP applications to one or more web servers in certain situations. The deployment process would then start off by compiling the *.php source code files into *.php.bin files. These can then be packaged into an RPM package, for instance, for distribution to and activation on the web server(s).