PHP 7.4 is the latest version of the PHP programming language that will launch later this year. PHP 7.4 recently went into beta, so I started exploring the new features. One feature showing a lot of promise is called Opcache Preload. Using preload you can set PHP to load certain PHP files into memory on startup. Doing so reduces the amount of files PHP has to compile when receiving an HTTP request which improves performance. Before exploring preload, let us look at how opcache works in the PHP runtime.
Opcache Is Your Friend
In PHP, the term PHP is used for the programming language. However, the runtime that executes PHP code is called the Zend Engine. When the Zend Engine receives a request for a PHP file, it actually compiles the PHP file into a list of operation codes, hence the term opcode
. The opcache
Zend Engine extension stores those opcodes in memory after a PHP file is compiled, so that the PHP file does not have to be compiled again in subsequent requests for the file.
The opcache.preload
directive allows a PHP programmer to instruct the opcache to cache the opcodes for a set of PHP files when the Zend Engine is activated. The preload option should be pointed to a PHP file that runs the function opcache_compile_file
on the files you want preloaded.
Enabling Preload
To test preloading, I set up an example project that uses Slim 3 for routing.
To use preloading, you have to install PHP 7.4. I am using Ubuntu WSL on Windows with the ondrej/php PPA activated. Since I'm using Ondrej's PPA, I can run sudo apt install php7.4-fpm
in bash to get the latest 7.4 beta on my system. I use the FPM installation with Nginx as my web server and a host entry called preloading.local
pointed at my project. After installation, I opened the FPM php.ini file (located at /etc/php/7.4/fpm/php.ini
on my system) and changed the opcache.preload
option to the path to my preload.php
file in my project.
The preload.php
file uses a modified preload
function based on Dmitry Stogov's example in the Preload RFC. I have all the Slim dependencies loaded in a vendor
folder using Composer. I then use the preload
function in my preload.php
on all the Composer source files I need to run the Slim application. After restarting PHP FPM (sudo service php7.4-fpm restart
), I can open preloading.local
in my browser and see my application run successfully.
My Thoughts on Preload
- I like that I did not have to use the Composer autoloader for my framework. Since all of the framework code was preloaded, autoloading is unnecessary. I do hope that Composer will generate an automatic
preload.php
file, like theautoload.php
file, so that vendor dependencies can be preloaded easily. - The performance gain is miniscule for a small project like this one, however, I can see preloading being a great way to speed up large frameworks like Symfony, Laravel and especially Magento.
- Preloading will be tricky to implement if you have multiple PHP projects on the same server, since you can only set one file to be preloaded.
- I had an issue where preloading would not load the
functions.php
file in thenikic/fast-route
module because it was wrapped in anif
statement. I had to set up a patch file to manually load those functions without theif
statement. It is probably because 7.4 is still in beta or mypreload.php
needs to be improved. - I do not think many PHP developers will use preload in development environments. I generally am reluctant to use features in production that are unused in dev because of the potential for unseen issues to arise on production servers. However, the risk is pretty low for preloading, so it will still be worth it to have it enabled.
All in all, I'm really looking forward to the performance gains from preloading. PHP is already one of the fastest scripting languages on the web and I am happy that the core team continues to push PHP into faster territories.
Next, I want to try arrow functions, the foreign function interface and typed properties. There are a lot of great features being added to PHP soon!
Top comments (3)
I'm also quite curious about how this will be used in practice.
Do you have to reload php to clear the opcache? Can you just give it a directive to re-cache a file if it was modified? If the original file was moved, does the cache still apply? If the original was changed is the cache now inaccurate?
I also wonder if this will benefit some of PHP core libraries that are written in PHP... or just userland stuff?
Looking forward to more info coming out.
You will have to restart PHP to update the files that were preloaded (another reason why it will not be used in dev). I'm sure there will be plenty of benchmarks when 7.4 is released. However, it's going to take some time for the big frameworks to enable compatibility.
FYI to Point 4: By design only top-level entities are preloaded. See RFC Section