PHP applications often execute the same source code across thousands of requests. Without bytecode caching, PHP must parse and compile PHP files before executing them. Although PHP handles this process efficiently, repeating it unnecessarily can increase CPU usage and response time under sustained traffic.
OPcache addresses this problem by storing compiled PHP bytecode in shared memory. When a request executes a PHP file that is already cached, PHP can reuse the compiled bytecode instead of compiling the file again.
For applications running inside Docker containers, enabling OPcache requires more than installing an extension. Developers must configure memory limits, understand how configuration changes interact with container builds, and decide how cached bytecode should behave when application files change.
A configuration that works during local development may not be appropriate for production. For example, checking file timestamps on every request can introduce unnecessary overhead, while disabling timestamp validation without a reliable deployment strategy can cause PHP to continue executing outdated code.
This article explains how OPcache works, how to enable it in a Dockerized PHP application, which settings matter in production, and how to verify that the configuration behaves as expected.
What Is PHP OPcache?
OPcache is a PHP extension that improves performance by caching compiled PHP bytecode.
When PHP executes a source file, it typically performs several operations:
Reads the PHP source file.
Parses the source into an internal representation.
Compiles the code into opcode instructions.
Executes those instructions.
Without a persistent bytecode cache, the compilation work may be repeated across requests.
OPcache stores compiled opcode in shared memory so subsequent requests can reuse it. The operating system and PHP runtime still perform other work, including executing application logic, accessing databases, handling HTTP requests, and rendering responses.
OPcache does not cache every aspect of an HTTP response by default. It is different from a full-page cache, an HTTP reverse-proxy cache, or an application-level data cache.
Why OPcache Matters in Docker
A Docker container does not automatically enable OPcache simply because it runs PHP.
The extension must be available in the PHP image, enabled in the PHP configuration, and configured appropriately for the application's workload.
For example, a container serving a Laravel application might handle many requests that load the same controller classes, service classes, middleware, and framework code. OPcache can reuse compiled bytecode for those files across PHP requests handled by the same PHP runtime environment.
The performance improvement depends on the application, traffic pattern, available memory, and other bottlenecks. OPcache cannot compensate for inefficient database queries or excessive network calls.
Installing OPcache in a PHP Docker Image
Official PHP Docker images commonly include the OPcache extension source, allowing it to be installed with the docker-php-ext-install helper.
The exact setup depends on the selected PHP image and deployment environment.
Example Dockerfile
The following example uses an official PHP-FPM image:
FROM php:8.4-fpm
RUN docker-php-ext-install opcache
COPY docker/php/opcache.ini \
/usr/local/etc/php/conf.d/zz-opcache.ini
WORKDIR /var/www/html
COPY . /var/www/html
This Dockerfile performs four main tasks.
Selects a PHP-FPM image.
Installs the OPcache extension.
Copies the custom OPcache configuration into PHP's configuration directory.
Copies the application source into the image.
The PHP version is illustrative. Choose a PHP release that is supported by your application and dependencies, and pin the image to an appropriate version or digest according to your deployment policy.
The zz-opcache.ini filename helps place the configuration late in the typical configuration-loading order, but developers should verify the actual configuration files loaded by their selected image.
For production builds, also consider using a .dockerignore file to prevent local development files, credentials, test artifacts, and unnecessary dependencies from entering the image.
Verify That OPcache Is Installed
After building the image, check whether PHP recognizes the extension.
docker build -t my-php-app .
docker run --rm my-php-app php -m
Look for Zend OPcache in the module list.
You can also inspect the configuration:
docker run --rm my-php-app php --ri "Zend OPcache"
These commands verify the CLI environment. They do not, by themselves, prove that PHP-FPM is loading the same configuration or using the same runtime settings.
For a PHP-FPM deployment, inspect the running container as well:
docker exec -it php-app php --ri "Zend OPcache"
Replace php-app with the actual container name.
The command provides useful information about the extension and its configuration. For settings that depend on the SAPI, confirm the values through the actual PHP-FPM environment or an appropriately secured diagnostic endpoint.
Configuring OPcache for Production
PHP reads OPcache settings from its configuration files. For a containerized deployment, keeping those settings in a version-controlled file makes the configuration easier to review, reproduce, and deploy.
Create a file named docker/php/opcache.ini.
Recommended Starting Configuration
; Enable OPcache for the PHP runtime.
opcache.enable=1
; Allocate shared memory for cached bytecode.
opcache.memory_consumption=128
; Allocate memory for interned strings.
opcache.interned_strings_buffer=16
; Maximum number of cached script keys.
opcache.max_accelerated_files=20000
; Validate cached scripts against source-file timestamps.
opcache.validate_timestamps=0
; Keep runtime optimization enabled.
opcache.enable_file_override=0
These values are a starting point, not a universal production configuration. Memory requirements and the appropriate number of cached scripts depend on the application and the size of its dependency tree.
The following settings deserve particular attention.
1. opcache.memory_consumption
This setting controls the shared memory allocation used by OPcache for cached scripts and associated metadata.
opcache.memory_consumption=128
The value is expressed in megabytes.
A larger application with many PHP files may require more memory than a small API. If the cache does not have enough capacity, scripts may fail to remain cached as intended.
Do not increase this setting without checking actual usage. Shared memory allocated to OPcache also contributes to the container's overall memory requirements.
Monitor OPcache statistics and container memory consumption before changing the value.
2. opcache.interned_strings_buffer
PHP applications often use repeated strings, including class names, method names, and other identifiers.
opcache.interned_strings_buffer=16
This setting allocates memory for interned strings used by the runtime and OPcache.
The appropriate value depends on the application. A large framework with many dependencies may benefit from a larger allocation than a small script-based service.
Review runtime statistics rather than assuming that every application needs the same setting.
3. opcache.max_accelerated_files
This setting controls the number of script keys that can be stored in the OPcache hash table.
opcache.max_accelerated_files=20000
A framework application can load thousands of PHP files through its own code and installed dependencies.
If the configured capacity is too small, the cache may not accommodate the desired number of scripts.
Choose a value based on the application's file count and observed cache behavior. Do not confuse this setting with the amount of bytecode memory available; memory_consumption and script-key capacity address different constraints.
4. opcache.validate_timestamps
This setting determines whether OPcache checks whether cached scripts have changed.
opcache.validate_timestamps=0
When timestamp validation is disabled, OPcache does not automatically discover source-file changes through normal timestamp validation.
This can be appropriate for immutable production images, where the application code is fixed for the lifetime of a deployed release.
However, it creates an important deployment requirement: when the application code changes, the relevant PHP runtime must be restarted or the cache must be reset through a supported deployment mechanism.
If your deployment process modifies PHP files in place without restarting PHP-FPM, disabling timestamp validation can cause outdated code to remain in use.
For development environments, timestamp validation is usually more convenient.
5. opcache.enable_file_override
This setting enables a specific optimization that can allow certain file-related functions to use OPcache information.
opcache.enable_file_override=0
It is not necessary to enable this option simply to benefit from bytecode caching.
Keep the default behavior unless profiling and application testing show that changing it is appropriate. Filesystem-related assumptions can be significant for applications that inspect files dynamically.
Using Different OPcache Settings for Development and Production
Development and production have different requirements.
During development, files change frequently. Developers expect code edits to become visible without rebuilding the container or restarting PHP after every change.
In production, application files are often packaged into an immutable image and replaced as part of a deployment.
A useful approach is to maintain separate configuration files for these environments.
Development Configuration
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=0
With timestamp validation enabled and the revalidation frequency set to zero, PHP checks file timestamps on each applicable request rather than waiting for a positive revalidation interval.
This is useful for development, although it can introduce filesystem-checking overhead.
Production Configuration
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
This production example assumes the application code remains unchanged inside a running release.
If your deployment process mounts source files from the host or updates code in place, revisit this assumption. Production settings should reflect the actual deployment model, not simply a conventional recommendation.
Also, keep development and production configuration differences explicit. Avoid relying on developers to remember which settings need to be changed manually before building a release.
Docker Deployment Strategies and OPcache
OPcache configuration is closely connected to how an application is deployed.
A good deployment strategy ensures that the running PHP process uses the correct application code and the corresponding cache state.
Strategy 1: Immutable Container Images
In an immutable deployment, the application code and PHP configuration are packaged into a versioned image.
When a new release is deployed, the orchestrator starts new containers using the new image.
This approach works well with timestamp validation disabled because the PHP code is not expected to change inside an existing container.
A simplified deployment sequence is:
Build an image containing the updated application.
Run automated tests against the image.
Publish the image with a unique version or digest.
Deploy the new image.
Verify application health and monitor errors.
Retire the previous containers after the new release is ready.
This strategy reduces the risk of running new files with stale cached bytecode.
For deployments requiring high availability, use a rolling or otherwise controlled replacement strategy that maintains service capacity while new containers start.
Strategy 2: Restart PHP-FPM After Code Changes
Some deployments update files within an existing environment.
If timestamp validation is disabled, changing the files alone may not update cached bytecode. Restarting the relevant PHP-FPM process can ensure that the new runtime starts with the updated code and a fresh cache.
For a containerized application, this may mean replacing or restarting the container, depending on the deployment architecture.
Avoid assuming that restarting a web server automatically restarts PHP-FPM when they run in separate containers.
Strategy 3: Reset the Cache During Deployment
OPcache provides functions and administrative mechanisms for resetting cached scripts, subject to the runtime and access permissions.
For example:
<?php
if (function_exists('opcache_reset')) {
$reset = opcache_reset();
echo $reset
? 'OPcache reset successfully.'
: 'OPcache reset failed.';
}
This example illustrates the API, but it should not be exposed as an unrestricted production endpoint.
An OPcache reset endpoint can create operational and security problems if unauthorized users can trigger it. It may also affect performance while the cache is repopulated.
Prefer a controlled deployment command or a runtime restart when appropriate. If a reset mechanism is necessary, restrict it to trusted administrative execution and ensure that it targets the intended PHP runtime.
Monitoring OPcache in Production
Enabling OPcache is only the first step. Monitoring helps determine whether the cache has enough capacity and whether its behavior is consistent with the application's workload.
Useful statistics include:
PHP provides opcache_get_status() for retrieving cache statistics when the function is available and permitted in the current runtime.
Example: Inspecting OPcache Statistics
<?php
if (!function_exists('opcache_get_status')) {
throw new RuntimeException(
'OPcache status information is unavailable.'
);
}
$status = opcache_get_status(false);
if ($status === false) {
throw new RuntimeException(
'Unable to retrieve OPcache status.'
);
}
$memory = $status['memory_usage'] ?? [];
$statistics = $status['opcache_statistics'] ?? [];
echo 'Cache enabled: ' .
(($status['opcache_enabled'] ?? false) ? 'Yes' : 'No') .
PHP_EOL;
echo 'Cached scripts: ' .
($statistics['num_cached_scripts'] ?? 'Unknown') .
PHP_EOL;
echo 'Cache hits: ' .
($statistics['hits'] ?? 'Unknown') .
PHP_EOL;
echo 'Cache misses: ' .
($statistics['misses'] ?? 'Unknown') .
PHP_EOL;
echo 'Used memory: ' .
($memory['used_memory'] ?? 'Unknown') .
PHP_EOL;
The second argument to opcache_get_status() is set to false so the example does not request the list of individual cached scripts.
The status data can help identify whether the cache is enabled and how it is being used.
Do not publish this diagnostic output through an unauthenticated public endpoint. Operational statistics may expose implementation details that should not be available to external users.
For long-running production environments, collect relevant statistics through a protected monitoring mechanism and alert on sustained problems rather than reacting to a single measurement.
Common OPcache Problems in Docker
OPcache Is Installed but Not Enabled
The extension may appear in the module list while the intended configuration is not loaded.
Check the active PHP configuration:
php --ini
php --ri "Zend OPcache"
Run these commands inside the relevant container.
Remember that CLI and PHP-FPM can use different settings. Verify the configuration for the SAPI that actually serves application requests.
Application Changes Do Not Appear
If opcache.validate_timestamps=0, PHP may continue executing previously cached bytecode after the source files change.
Confirm that the deployed container contains the expected source files and that the relevant PHP runtime has been restarted or its cache has been refreshed appropriately.
The Cache Runs Out of Capacity
An application with a large number of classes and dependencies may exceed its configured script-key capacity or shared memory allocation.
Inspect OPcache statistics, then adjust opcache.max_accelerated_files or opcache.memory_consumption based on the observed constraint.
Increasing both settings without checking actual usage can waste memory without addressing the underlying issue.
Container Memory Usage Increases
OPcache uses shared memory, which contributes to the resource requirements of the PHP environment.
When configuring containers, account for OPcache, PHP workers, application memory, extensions, and other processes that share the container's memory limit.
If PHP-FPM runs multiple worker processes, understand how shared memory and per-process memory consumption contribute to the total. Do not assume that the configured OPcache allocation represents the entire memory requirement of the container.
Best Practices for Production
Install OPcache as part of the application image rather than relying on manual changes to a running container.
Keep configuration files version-controlled and separate development settings from production settings.
Disable timestamp validation only when the deployment process reliably replaces or refreshes the relevant PHP runtime after code changes.
Monitor cache hits, memory usage, script counts, and cache restarts.
Choose memory and script-key limits based on actual application requirements.
Verify settings in PHP-FPM, not only in the CLI environment.
Avoid exposing OPcache diagnostic or reset functions through unrestricted public endpoints.
Benchmark representative requests before and after enabling OPcache.
Treat OPcache as a bytecode optimization, not a replacement for database optimization, HTTP caching, or application-level performance improvements.
Include OPcache configuration checks in the release validation process.
Advantages and Limitations of OPcache
Advantages | Limitations |
|---|
Reuses compiled PHP bytecode across requests | Does not eliminate application execution costs |
Can reduce repeated parsing and compilation work | Requires appropriate memory allocation |
Fits naturally into Docker image builds | Incorrect timestamp settings can leave stale code active |
Supports measurable cache statistics | Requires monitoring and deployment discipline |
Works with many PHP frameworks and applications | Does not directly cache complete HTTP responses |
Conclusion
PHP OPcache is a practical performance optimization for Dockerized PHP applications because it allows the runtime to reuse compiled bytecode rather than repeatedly compiling the same source files.
A reliable production setup involves installing the extension in the image, maintaining an explicit configuration file, choosing suitable memory and script limits, and verifying the settings in the PHP runtime that serves requests.
The most important deployment decision concerns source-file changes. Disabling timestamp validation can reduce repeated file checks, but it requires a deployment process that reliably refreshes the relevant runtime when application code changes.
Start with a conservative configuration, measure cache behavior under realistic traffic, and adjust settings based on observed memory usage and application size. When combined with immutable images, controlled deployments, and monitoring, OPcache can become a predictable part of a production PHP performance strategy.
Join the conversation! Your thoughts help the community grow.