Opcache — How PHP Compiles & Caches Bytecode
Every PHP request without Opcache re-parses and re-compiles every included file from scratch. Opcache stores the compiled bytecode in shared memory — subsequent requests reuse it, cutting request startup from ~10ms to ~1ms. Understanding Opcache configuration is critical for any production PHP deployment.
Opcache Internals & Configuration
# ── How PHP executes a request WITHOUT Opcache ─────────────────
# 1. PHP reads raw source files (fopen + fread)
# 2. Lexer tokenises source into tokens
# 3. Parser builds Abstract Syntax Tree (AST) from tokens
# 4. Compiler converts AST to Zend opcodes (bytecode)
# 5. Zend Engine executes opcodes
# Steps 1-4 happen on EVERY request — even if files haven't changed!
#
# ── WITH Opcache ───────────────────────────────────────────────
# First request: Steps 1-4 run, result stored in shared memory
# All later requests: Skip to step 5 — execute from cached bytecode
# Result: ~10x faster startup
# ── php.ini Opcache configuration (production settings) ────────
[opcache]
opcache.enable = 1
opcache.enable_cli = 0 ; Don't cache CLI runs (dev loops)
opcache.memory_consumption = 256 ; MB of shared memory
opcache.interned_strings_buffer = 16 ; MB for interned strings pool
opcache.max_accelerated_files = 20000 ; Max files in cache (>total PHP files in project)
opcache.validate_timestamps = 0 ; PRODUCTION: don't check mtime (use 1 in dev)
opcache.revalidate_freq = 0 ; Seconds between mtime checks (irrelevant if validate=0)
opcache.fast_shutdown = 1 ; Faster request shutdown
opcache.save_comments = 1 ; Keep docblocks (needed for Doctrine/annotations)
opcache.preload = /var/www/html/preload.php ; PHP 7.4+: preload important classes
# ── validate_timestamps = 0 in production ──────────────────────
# With validate_timestamps=0: PHP never checks if source files changed.
# After deploying new code: must call opcache_reset() or restart PHP-FPM!
# Without restart: old bytecode still served — users see old code!
# ── preload.php — PHP 7.4+ preloading ────────────────────────
# Classes preloaded into shared memory at PHP-FPM startup
# Available to ALL workers without re-compiling
# Only for classes that are used on EVERY request
<?php
// preload.php — preload core framework classes
$classes = [
__DIR__ . "/src/Http/Request.php",
__DIR__ . "/src/Http/Response.php",
__DIR__ . "/src/Http/Router.php",
__DIR__ . "/src/Blog/Domain/Post.php",
__DIR__ . "/src/Blog/Service/PostService.php",
];
foreach ($classes as $file) {
opcache_compile_file($file);
}
<?php
// ── Inspecting Opcache at runtime ─────────────────────────────
$status = opcache_get_status();
echo "Cache full: " . ($status["cache_full"] ? "YES — increase memory!" : "No") . "
";
echo "Cached scripts: " . $status["opcache_statistics"]["num_cached_scripts"] . "
";
echo "Cache hits: " . $status["opcache_statistics"]["hits"] . "
";
echo "Cache misses: " . $status["opcache_statistics"]["misses"] . "
";
echo "Hit rate: " . round($status["opcache_statistics"]["opcache_hit_rate"], 2) . "%
";
echo "Memory used: " . round($status["memory_usage"]["used_memory"] / 1048576, 2) . " MB
";
echo "Memory free: " . round($status["memory_usage"]["free_memory"] / 1048576, 2) . " MB
";
// Invalidate one file after deploy
opcache_invalidate("/var/www/html/src/Blog/Service/PostService.php", force: true);
// Clear entire cache (call after deployment)
opcache_reset();Quick Quiz
Tip
Tip
Practice Opcache How PHP Compiles Caches Bytecode in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
PHP processes each request through the server-side engine
Practice Task
Note
Practice Task — (1) Write a working example of Opcache How PHP Compiles Caches Bytecode from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Common Mistake
Warning
A common mistake with Opcache How PHP Compiles Caches Bytecode is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready php code.