OPcache and JIT
OPcache works out of the box with OxPHP. All PHP worker threads share a single OPcache memory segment. Scripts are compiled once at first execution and served from the cache by every worker thereafter. No special setup is required to enable this sharing.
How OPcache works with OxPHP
OxPHP registers itself as a named SAPI, and OPcache treats it identically to other server SAPIs. The key characteristics are:
- Shared cache across workers: all PHP worker threads use the same compiled opcode cache. One worker compiles a file; all workers benefit.
- No per-request compilation: after the first request for each script, subsequent requests skip the parse and compile step entirely.
opcache.enable_clidoes not affect OxPHP. That setting applies only to SAPIs namedcliandphpdbg. OxPHP registers with the SAPI namecli-server, so OPcache is controlled solely viaopcache.enable. Theopcache.enable_clisetting is useful if you run PHP CLI in the same container (e.g., for migrations or Artisan commands). The official OxPHP image ships PHP CLI alongside the server binary, so you can setopcache.enable_cli=1if your CLI scripts benefit from caching.
To enable OPcache, at minimum:
[opcache]
opcache.enable=1The official OxPHP Docker image is based on php:*-zts-alpine, which compiles OPcache statically into the PHP binary. Do NOT add zend_extension=opcache to your INI file. The extension is already loaded, and adding that line will cause a warning on every PHP startup. Only the [opcache] configuration section is needed.
Recommended production settings
These settings are optimized for production container deployments where PHP files do not change at runtime. Disable timestamp validation and preload compiled files at startup for maximum throughput.
[opcache]
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.file_update_protection=0
opcache.jit_buffer_size=64M
opcache.jit=tracing| Setting | Recommended Value | Description |
|---|---|---|
memory_consumption |
128 |
Shared memory in MB for compiled scripts. Increase if opcache_get_status() shows low free memory. |
interned_strings_buffer |
16 |
Memory in MB for interned strings shared across all workers. |
max_accelerated_files |
10000 |
Maximum number of cached scripts. Set this higher than your total .php file count. |
validate_timestamps |
0 |
When 0, OPcache never checks the filesystem for changes. Restart the container or call opcache_reset() to pick up code changes. |
revalidate_freq |
0 |
Seconds between filesystem checks. Has no effect when validate_timestamps=0. |
file_update_protection |
0 |
Seconds after file modification before the file is eligible for caching. Set to 0 to cache immediately at startup. |
Development settings
For development, enable timestamp validation so code changes take effect without restarting the container. Disable JIT to get clearer stack traces during debugging.
[opcache]
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2
opcache.jit_buffer_size=0
opcache.jit=disableWith validate_timestamps=1, OPcache checks file modification times every revalidate_freq seconds. This adds a small per-request overhead but lets you edit PHP files and see changes on the next request.
This is the recommended development-mode reload strategy for OxPHP. OPcache performs the check inline on every include, so code edits are picked up at the next request with no container restart and no external file-watcher daemon. Use revalidate_freq=0 for immediate stat-per-include (highest accuracy, slightly more I/O), or revalidate_freq=2 to amortize the stat cost. The default shown above is a good balance, especially if your DOCUMENT_ROOT is on a slow bind-mount (Docker on macOS/Windows).
What is NOT reloaded by validate_timestamps
A few classes of changes still require a container restart (or worker recycle) even with validate_timestamps=1:
- Preloaded files (
opcache.preload) are linked into the server at startup and are never revalidated. Edit a preloaded file — restart the container. - Worker Mode bootstrap state — in Worker Mode, the autoloader, DI container, and any objects built in the outer scope live in worker memory. OPcache will recompile changed class files, but the worker will not re-run its bootstrap. For dev worker loops, call
Worker::scheduleExit()at the end of each request (e.g. behind anOXPHP_DEVenv flag) to recycle the worker, which re-executes the outer scope and picks up all changes. - Framework-level caches — compiled Symfony container, Laravel route/config/view cache, Composer optimized classmap. These are
.phpfiles OPcache revalidates, but the values inside them reference stale class paths or container IDs. Run the framework'scache:clearcommand; OPcache alone is not enough. - Non-PHP files —
.env,composer.json, YAML/JSON config, template files compiled outside OPcache. OPcache tracks only files it compiled; everything else needs a restart.
JIT compilation
OPcache's JIT compiler translates PHP opcodes into native machine code at runtime. Use tracing mode for the best optimization:
opcache.jit=tracing
opcache.jit_buffer_size=64MJIT provides the most benefit for CPU-bound PHP code: math-heavy loops, string processing, image manipulation, and template rendering. For I/O-bound applications that spend most of their time waiting on database queries or external API calls, the improvement is minimal.
To disable JIT:
opcache.jit=disable
opcache.jit_buffer_size=0Preloading
OPcache preloading compiles and caches PHP files at server startup, before any requests are handled. This eliminates first-request compilation cost entirely and makes classes and functions available globally without any require or autoload overhead.
Configure preloading in your INI file:
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-dataCreate a preload.php script that loads your most frequently used files:
<?php
// preload.php — runs once at server startup
require __DIR__ . '/vendor/autoload.php';
// Preload framework core files
$files = glob(__DIR__ . '/vendor/symfony/http-kernel/**.php');
foreach ($files as $file) {
opcache_compile_file($file);
}
// Preload hot application paths
opcache_compile_file(__DIR__ . '/src/Controller/ApiController.php');
opcache_compile_file(__DIR__ . '/src/Service/UserService.php');Preloaded classes and functions are permanently available to all requests. They cannot be changed without restarting the server.
If you use Worker Mode, your application is already initialized once: the autoloader, configuration, and database connections persist between requests. OPcache preloading complements this by eliminating opcode compilation overhead, but it does not replace application initialization. The two mechanisms work independently and can be used together.
Applying the PHP configuration
OxPHP reads PHP configuration from the standard conf.d directory. Use a Docker volume or a COPY instruction to supply your custom INI file.
docker run -p 80:80 \
-v ./custom.ini:/usr/local/etc/php/conf.d/custom.ini:ro \
ghcr.io/oxphp/oxphp:0.10.0FROM ghcr.io/oxphp/oxphp:0.10.0
COPY custom.ini /usr/local/etc/php/conf.d/custom.ini
COPY --chown=www-data:www-data . /var/www/htmlservices:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "80:80"
volumes:
- ./custom.ini:/usr/local/etc/php/conf.d/custom.ini:ro
- ./src:/var/www/htmlMonitoring cache status
Inspect the live OPcache status from PHP to verify it is working:
<?php
$status = opcache_get_status();
echo "Cached scripts: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";
echo "Cache hits: " . $status['opcache_statistics']['hits'] . "\n";
echo "Cache misses: " . $status['opcache_statistics']['misses'] . "\n";
echo "Free memory: " . $status['memory_usage']['free_memory'] . " bytes\n";If free_memory is consistently low, increase opcache.memory_consumption.
See also
- Docker Guide -- container setup and mounting configuration files
- Configuration Reference -- environment variables for OxPHP
- Worker Mode -- persistent PHP processes that benefit most from OPcache