PHP 7.4 was released a few days ago and it's the most exciting PHP release in years. It includes game-changing features such as typed properties, arrow functions, covariant types, FFI (Foreign Function Interface), OPCache preloading and more.
OPCache Preloading
At the very beginning, PHP parsed and compiled any file used to serve a request. The parsing/compiling result (called "opcodes") was not reused for other requests, so the exact same process had to be repeated again and again.
On production servers, the code of your PHP files does not change between requests, so the parsing and compiling result can be reused. That's what the OPCache does (OPCache = "opcodes cache"), improving the overall performance between 2 and 15 times.
However, the OPCache doesn't remove other execution costs: PHP still has to check if the source file was modified, copy certain parts of classes and functions from the shared memory cache to the process memory, etc. Moreover, since each PHP file is compiled/cached completely independently from any other file, PHP can't resolve dependencies between classes stored in different files and has to re-link the class dependencies at run-time on each request.
PHP 7.4 can eliminate most of these costs thanks to preloading. On server startup - before any application code is run - PHP can load a certain set of PHP files into memory and make their contents permanently available to all subsequent requests.
All the functions and classes defined in these files will be available to
requests out of the box, exactly like internal entities (e.g. strlen()
or
Exception
). In fact, PHP can preload entire or partial frameworks like
Symfony, and even the entire application class library.
OPCache Preloading in Practice
Preloading is controlled by a new php.ini directive called opcache.preload
.
The value of this directive is the path of the PHP file that preloads the files
using either include_once
or opcache_compile_file()
.
During preloading, PHP also resolves class dependencies and links with parent, interfaces and traits. It also removes unnecessary includes and performs some other optimizations. The overall result is a performance improvement of 30%-50% in real applications.
Keep in mind that preloaded files remain cached in OPCache memory forever. If you change the source code of any preloaded file, you'll need to restart the web server or changes won't have any effect.
OPCache Preloading in Symfony
Thanks to the internal Symfony behavior of compiling files before running the
application (e.g. the service container) we can introduce support for preloading
with only a few changes. That's why Symfony 4.4 can generate a preloading file
for your application in the cache directory. The generated file name includes
both the environment and kernel names (e.g. var/cache/dev/App_KernelDevDebugContainer.preload.php
).
You can use this generated file as the value of the opcache.preload
PHP directive:
1 2
; php.ini
opcache.preload=/path/to/project/var/cache/prod/App_KernelProdContainer.preload.php
The next step will be to allow applications and bundles to declare which of their classes should be preloaded too. Check out the Pull Request #33689 to see the work in progress feature to do that.
If you are already running PHP 7.4, please test this feature in your real projects and report the performance improvement. Or even better, publish a blog post with the details and we'll feature it in the next A Week of Symfony post.
One thing that might be confusing, is the part that states "you'll need to restart the server or changes won't have any effect". I think it should be noted that you don't have to reboot the entire server, but just restarting apache or the php-fpm service should be sufficient.
@Pierre good catch! I've updated the post to say "restart the web server" instead of "restart the server". Thanks!
Restart the webserver on every deploy? Reload fpm is not enough? Or restart only once to pick up the config?
@Youssef: Nah, I am pretty sure that reloading FPM should suffice
This feature is very cool but we have to have one server by project otherwise the preloading won't work for other project.
@Youssef : you will have to restart (not only reload) the web server check the PHP rfc : https://wiki.php.net/rfc/preload
Nice feature! I am curious to the benchmark results
I did some initial benchmarks, but with a large number of dependencies I got quite a bit of segfaults that I did not have time (or the skills) to resolve. Still a very impressive boost over PHP 7.3 even without OPCache Preloading!
Results here: https://ezplatform.com/blog/benchmarking-php-7.3-vs-7.4-with-symfony-4.4-trouble-with-opcache-preloading
@Jani the preload feature is quite new in PHP, and it has bugs. PHP 7.4.1 will have fixes for these segfaults (well, at least for some of them)
and do not forget to set
opcache.preload_user=www-data
""" You can use this generated file as the value of the opcache.preload PHP directive:
; php.ini opcache.preload=/path/to/project/var/cache/prod/App_KernelProdContainer.preload.php """
How does one generate that file? It does not appear to be generating automagically for me in v5.0.2. Or was this strictly for Symfony 4.4?