PHP 8 Performance: Achieve noticeable speed gains
PHP 8 brought real leaps in performance and developer productivity. But the defaults don't unlock the potential. With the right configuration, significant improvements are regularly achieved for compute-intensive workloads — entirely without redesigning the application. This is especially true for SMEs, where PHP applications often run for years and a version upgrade needs careful preparation. A targeted look at OPcache, JIT and preloading pays off: the effort is modest, the leverage considerable depending on the workload — and unlike a full code-rewrite migration, these levers can be activated gradually, with no risk.
Using JIT correctly
The Just-In-Time compiler is the killer feature of PHP 8. Misconfigured, it can even degrade performance.
; php.ini — sensible defaults
opcache.enable=1
opcache.jit_buffer_size=256M
opcache.jit=1235 ; tracing JIT, good for CPU-bound logic
; opcache.jit=1254 ; for web apps with many function calls
JIT delivers the most for compute-intensive code — image processing, calculations, parsing. For classic I/O-bound web requests, the effect is smaller; there OPcache matters more. The JIT buffer deserves deliberate sizing: setting jit_buffer_size to 256 MB reserves that memory consistently. On a well-equipped server this is no problem; on a small VM it gets tight quickly. It is also important to activate the JIT mode explicitly via opcache.jit — without an explicit value, PHP in some builds simply keeps interpreting.
OPcache & Preloading
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; in production: don't constantly check the cache
opcache.preload=/var/www/preload.php
Preloading loads framework classes once at startup into memory — every request starts already "warmed up". This pays off particularly for large frameworks like Symfony or Laravel, where hundreds of classes would otherwise be loaded per request. If you disable validate_timestamps in production, you must actively propagate file changes — for example via an OPcache reset during deployment, otherwise the old version keeps running. The effect is measurable: where every request used to cost a slice of compile time, that share now almost disappears.
Common pitfalls
The most common performance killers sit not in the code but in the configuration. An OPcache whose memory_consumption is set too low silently evicts entries — the supposed acceleration fizzles out. The log often says nothing about it; you recognize it only by an unusually high number of cache misses. max_accelerated_files should be generously sized; 20,000 is a solid value for medium-sized applications, large monoliths need more. And preloading requires the deployment to reload the preload.php after an update, otherwise the workers operate on a stale state. Forget that and you chase odd bugs that only vanish after a restart.
Measure instead of guess
Every optimization needs verification. A simple benchmark shows whether the JIT setting helps for the specific workload:
$start = hrtime(true);
// ... workload ...
printf("%.2f ms\n", (hrtime(true) - $start) / 1e6);
The rule remains: first measure, then configure, then measure again. Generic "speed tips" from the internet often do more harm than good. When in doubt, a real load test on the target hardware — and a comparison against the documented baseline — makes the decision. Recording the numbers before and after the change also gives you an argument when the next version jump comes around.
Does the JIT compiler help our typical web application at all?+
Only conditionally. JIT delivers the most for compute-intensive code like image processing, calculations, or parsing. For classic I/O-bound web requests the effect is smaller; there OPcache matters more. Before activating JIT, measure the concrete workload. Misconfigured, it can even degrade performance, so the rule is: benchmark first, then set jit_buffer_size and opcache.jit deliberately.
How do we enable OPcache and preloading without endangering the deployment?+
Set memory_consumption and max_accelerated_files generously, around 256 MB and 20000 files for medium-sized applications. Turn off validate_timestamps in production so the cache is not constantly checked. Importantly, preloading loads framework classes at startup, so the deployment must reload the preload.php after every update and trigger an OPcache reset, otherwise the old version keeps running.
What are the most common performance killers in PHP 8?+
They usually sit in the configuration, not the code. An OPcache memory_consumption set too low silently evicts entries, recognizable only by an unusually high number of cache misses. Too small a value for max_accelerated_files does the same. Also, forgetting the OPcache reset during deployment leaves the workers on a stale state, producing odd bugs that vanish only after a restart.