PHP discards everything at the end of each request, so keeping data for the next one usually means reaching for APCu or a service like Redis. This RFC from Go Kudo builds a cache into OPcache instead. It stores values in shared memory that every PHP worker can read, and it can also keep selected static properties alive between requests.
Why change it
APCu has to copy and rebuild values every time you store or fetch them. For large arrays and objects that's slow, even when you only need a small part of the data.
A lot of code already caches in static variables:
final class RouteMetadata { public static function compiled(): array { static $routes = null; return $routes ??= self::compileRoutes(); } }
That's fast, but the cached value is thrown away when the request ends. The author first tried to solve this as a separate extension, but it needed too many engine hooks, so the RFC puts it in OPcache.
Show me
There are two caches, each exposed through static methods. Here's the volatile one:
$miss = new stdClass(); $value = OPcache\VolatileCache::get('routes', $miss); if ($value === $miss) { $value = build_routes(); OPcache\VolatileCache::set('routes', $value, ttl: 300); }
And here's an attribute that keeps a class's static state across requests:
#[OPcache\PinnedStatic] final class Metadata { public static array $routes = []; } Metadata::$routes = ['foo']; // stored right away Metadata::$routes[] = 'bar'; // the change is stored too
How it works
OPcache\VolatileCacheworks like APCu. Entries can have a TTL, and they can be evicted when memory runs low.OPcache\PinnedCacheis for data that must not disappear. Entries have no TTL and are never evicted, so if a value won't fit, the store fails.#[OPcache\VolatileStatic]and#[OPcache\PinnedStatic]go on a class, a static property or a method, and keep that static state between requests.- Both caches have methods like
get(),set(),has(),delete()andclear(), pluslock()so only one request rebuilds a missing value. - Two INI settings,
opcache.static_cache.volatile_size_mbandopcache.static_cache.pinned_size_mb, set the sizes. Both default to 8 MB, and setting one to0turns it off.
The cache methods return false on failure, such as a full or disabled cache, while the pinned attributes throw OPcache\StaticCacheException instead. Under PHP-FPM, each pool gets its own cache, so one pool can't see another's data.
The RFC's benchmarks show reads much faster than APCu, though writes are slower.
What it means for existing code
Nothing changes unless you use the new classes, attributes or settings. The new names in the OPcache namespace become reserved.
Where it stands
The RFC is under discussion and targets PHP 8.6. It was last updated on June 2, 2026. Four votes are set up, one for each cache API and each attribute, and each needs a two-thirds majority. Voting has not started.