Before PHP executes a script, it reads the source code, parses it, and compiles it into what are called opcodes, that is, instructions for the PHP runtime. Without a cache, this is repeated on every request, even though the code usually has not changed. OPcache, short for opcode cache, stores the result in memory and saves this work. According to the PHP manual, the extension has been part of PHP since PHP 5.5.0. In production environments, it is part of the standard setup.
How OPcache works
- Cache in shared memory: The compiled bytecode resides in a memory area that all worker processes of a PHP-FPM service share.
- Change detection: By default, OPcache checks at intervals whether files have changed and then recompiles them.
- Preloading: Since PHP 7.4.0, a script can preload functions and classes at startup, which are then available to all requests. According to the manual, preloading is not supported on Windows.
- JIT compiler: Since PHP 8.0, OPcache can additionally compile parts of the code into machine code. Since PHP 8.4, the JIT is disabled by default (
opcache.jit=disable) and must be switched on deliberately.
Key settings
The default values according to the PHP manual; all settings begin with the prefix opcache.:
enable: 1, OPcache is activememory_consumption: 128 MB of memory for the cacheinterned_strings_buffer: 8 MB for strings used multiple timesmax_accelerated_files: 10000 scriptsvalidate_timestamps: 1, files are checked for changesrevalidate_freq: 2 seconds between two checks
Large applications with many libraries, for example based on Laravel, often need more memory and a higher value for the number of scripts. The function opcache_get_status() shows whether the values fit: if the memory is full or the hit rate drops, the cache is not working as intended.
In practice: OPcache and deployments
Many teams turn off opcache.validate_timestamps in production to save the file check. The PHP manual points out that OPcache then no longer detects changes. After every deployment, the cache must be cleared with opcache_reset() or the PHP service must be reloaded. If this step is missing from the CI/CD pipeline, the server keeps delivering the old code, sometimes mixed with new files.
A common approach is to roll out new versions into a separate directory, switch the link to it, and then reload PHP-FPM gracefully. This way, all processes switch to the new version together, and the way back to the previous version remains open.
Typical failure patterns
- After an update, old content or errors that should already have been fixed appear.
- The hit rate drops under load because
opcache.memory_consumptionoropcache.max_accelerated_filesare too small. - The JIT is enabled without measurement. Whether it helps a typical web application should be shown by a load test with realistic requests.
- On servers with several websites, applications unintentionally share resources.
Security
- OPcache's management functions, for example for clearing or reading the cache, can be restricted with
opcache.restrict_apito scripts in a specific path. This makes sense on servers with several applications. - Status output does not belong on the public web, because it reveals paths and file structure.
- Preloading loads classes for the entire lifetime of the process. According to the manual, websites should therefore not share a common process but use their own PHP-FPM pools.
- Plan and document changes to OPcache settings like any configuration change, see change management.
How it differs
OPcache stores compiled program code. Data caches such as APCu or Redis, by contrast, store results, such as database queries. Page caches and content delivery networks deliver entire responses without PHP running at all. The layers complement each other. How well they work together is shown by IT monitoring with response times and error rates.
Frequently asked questions
How can I tell whether OPcache is active?
Most reliably via opcache_get_status() on a protected diagnostics page or via the status output of your monitoring. Note: OPcache is turned off by default for the command line (opcache.enable_cli is set to 0). Running php -i in the shell therefore does not necessarily show the state of the web server.
Should I turn on the JIT?
Only after measuring. The JIT additionally compiles code into machine code and helps mainly with compute-intensive tasks. Many web applications, by contrast, spend their time on database queries and network access. Since PHP 8.4, the JIT must be enabled explicitly.
Do I have to clear OPcache after every update?
If opcache.validate_timestamps is active, OPcache detects changed files by itself after a short time. If the check is turned off, clearing or reloading must be a fixed part of every deployment.