OPcache is the PHP extension that stores precompiled script bytecode in shared memory, so that PHP does not have to read, parse and compile the same source files on every request. In server performance, it is one of the most effective single settings for PHP applications: it reduces CPU time per request, lowers latency and increases the throughput a PHP worker pool can sustain.
OPcache has been bundled with PHP since version 5.5 and is the standard opcode cache for PHP-FPM, Apache mod_php and command-line workers. It does not cache application data or HTML output; it caches compiled code, which is a different layer from object caches and page caches.
How OPcache removes repeated compilation
Without an opcode cache, PHP runs a full compile pipeline on every request: it reads each included file, tokenizes it, builds an abstract syntax tree and compiles it into opcodes, the instructions executed by the Zend Engine. For a framework that loads hundreds of files, that pipeline can consume a large share of request time.
OPcache intercepts compilation. The first request compiles a file and stores the resulting opcodes, together with interned strings and class metadata, in a shared memory segment used by all worker processes of the same pool. Later requests execute the cached opcodes directly, and the extension also applies optimizer passes such as constant folding and dead-code removal.
| Step | Without OPcache | With OPcache (warm cache) |
|---|---|---|
| Read source files | Every request | Only when revalidation detects a change |
| Tokenize and parse | Every request | Skipped |
| Compile to opcodes | Every request | Skipped |
| Optimize opcodes | Not performed | Once, at cache time |
| Execute opcodes | Every request | Every request |
Key OPcache settings and their ranges
OPcache is configured through php.ini directives, and default values are often too small for large applications. The most important settings control memory size, the number of cached files and how the cache notices code changes.
| Directive | Common values | What it controls |
|---|---|---|
| opcache.memory_consumption | 128-512 MB | Size of the shared memory segment in megabytes |
| opcache.interned_strings_buffer | 8-64 MB | Memory for deduplicated strings |
| opcache.max_accelerated_files | 10000-100000 | Maximum number of cached scripts |
| opcache.validate_timestamps | 1 in development, 0 in production | Whether file changes are checked |
| opcache.revalidate_freq | 0-60 seconds | How often timestamps are checked when enabled |
| opcache.jit_buffer_size | 0 or 64-256 MB | Memory for the JIT in PHP 8 and later |
With timestamp validation disabled, PHP never checks whether files changed, which saves file system calls but means a deployment must reset the cache explicitly, usually by reloading PHP-FPM. Teams that deploy by switching a symlink should also consider realpath cache behavior, because stale resolved paths can keep old code in use.
OPcache compared with other PHP caching layers
OPcache is often confused with other caches in a PHP stack. Each layer removes a different kind of repeated work, and a well-tuned server typically uses several of them together.
| Layer | What is cached | Scope |
|---|---|---|
| OPcache | Compiled bytecode of PHP files | Shared memory per PHP pool |
| OPcache preloading | Classes and functions loaded at startup | Whole pool, PHP 7.4 and later |
| JIT compiler | Machine code for hot opcode paths | Part of OPcache in PHP 8 and later |
| Object cache | Query results and computed data | Redis, Memcached or APCu |
| Page cache | Complete HTML responses | Reverse proxy, CDN or plugin |
The JIT benefits CPU-heavy computation such as image processing or mathematics, but typical database-bound web applications see modest gains from it, because their time is spent waiting on I/O rather than executing PHP instructions. Opcode caching itself, by contrast, helps almost every PHP workload.
Monitoring OPcache on a production server
OPcache exposes its state through opcache_get_status(), which reports memory usage, hit rate, cached script count and restart counters. A healthy production cache shows a hit rate close to 100 percent after warm-up and no out-of-memory restarts.
| Symptom | Likely cause | Fix |
|---|---|---|
| Frequent cache restarts | Memory segment full | Raise memory_consumption |
| Scripts not cached | max_accelerated_files too low | Raise it above the project file count |
| Old code after deployment | Validation disabled and no reset | Reload PHP-FPM as a deploy step |
| Interned strings buffer full | Large frameworks with many strings | Raise interned_strings_buffer |
| High wasted memory | Many invalidated scripts | Schedule a controlled reset during deployment |
Because the cache lives in each pool’s memory, the command-line interface has its own setting, opcache.enable_cli, which is usually off. Cron jobs therefore do not benefit from the web cache, and resetting OPcache from a CLI script does not clear the PHP-FPM cache.
Limitations and security considerations
- Shared pools on multi-tenant hosts: when several sites share one pool, cached code and status functions can leak information between them, so separate pools per site are advisable.
- Memory fragmentation: invalidated scripts are not freed immediately; wasted memory accumulates until a restart.
- Cold starts: after a reload, the first requests compile everything again and show higher latency, which matters on high-traffic servers.
- Not a fix for slow queries: OPcache removes compile time only; database and network latency remain unchanged.
Put simply
PHP code is written in a form people can read, and the server has to translate it before running it. Without OPcache, the server translates the same pages again for every visitor, like a chef rereading and reinterpreting a recipe for every plate.
OPcache keeps the translated version in memory. The translation happens once, and every later visitor gets the ready version, so the server does less work and answers faster.
In practice
A company runs a large PHP content platform on four application servers with PHP-FPM. Profiling shows that a significant part of each request is spent compiling about 3,000 framework files, and the status report reveals repeated cache restarts because the default memory segment is full.
The team raises opcache.memory_consumption to 256 MB, sets opcache.max_accelerated_files to 20000, disables timestamp validation and adds a PHP-FPM reload to the deployment script. Cache restarts stop, CPU usage per request drops noticeably, and the same servers handle traffic peaks that previously required adding a fifth node.