PHP Cache¶

PHP Cache provides small, interoperable caching packages for PHP. Version 3 requires PHP 8.2. PSR-6 adapters use psr/cache 3, and PSR-16 implementations support psr/simple-cache 2 and 3.
Start with the PSR cache introduction if you are new to PSR-6 or PSR-16. Cache implementers can use the integration test suite.
Cache adapters¶
Each adapter is available as a separate Composer package. All PHP Cache adapters support tags. Some also support hierarchical keys.
| Adapter | Composer package | Hierarchy |
|---|---|---|
| APCu | cache/apcu-adapter |
No |
| Array | cache/array-adapter |
Yes |
| Chain | cache/chain-adapter |
No |
| Doctrine | cache/doctrine-adapter |
No |
| Filesystem | cache/filesystem-adapter |
No |
| Illuminate | cache/illuminate-adapter |
Yes |
| Memcache | cache/memcache-adapter |
No |
| Memcached | cache/memcached-adapter |
Yes |
| MongoDB | cache/mongodb-adapter |
No |
| Predis | cache/predis-adapter |
Yes |
| Redis | cache/redis-adapter |
Yes |
| Void | cache/void-adapter |
Yes |
Install only the adapter your app needs:
composer require cache/redis-adapter:^3.0
The cache/cache metapackage installs the complete adapter collection:
composer require cache/cache:^3.0
Some adapters also require a PHP extension or client library. Check the adapter README before installation.
Upgrading to version 3¶
Version 3 stores a generation snapshot with each tagged item. Each tag also has a generation marker. Invalidating a tag removes its marker, so older item snapshots become cache misses.
The item payload and marker storage differ from version 2. Do not run version 2 and 3 workers against the same cache.
cache/adapter-common 3 reserves public cache keys that start with tag! or tagv!. Rename app keys that use either prefix.
Redis and Predis also replace tag sets with expiry-aware sorted sets under the reserved php-cache:tag: backend prefix.
Use this deployment sequence:
- Stop or drain every version 2 worker.
- Clear each shared cache.
- Deploy version 3 and restart the workers.
Use the same sequence before a rollback. The Array and Void adapters do not share stored values between workers.
Upgrading to version 2¶
Do not run version 2 workers alongside older workers when they share an affected cache store.
Version 2 changes these internal formats:
- APCu stores native arrays instead of serialized strings.
- Redis and Predis store tag indexes as sets instead of lists.
- Prefix and namespace components use reversible
_xHH_byte encoding. Bytes outside[A-Za-z0-9_.]and literal lowercase_xsequences are transformed. - Namespaced public key components preserve ordinary backend-supported bytes, including
-,%, and non-ASCII text. Only|,!, and literal lowercase_xsequences are transformed. - Namespaced tag indexes are isolated in version 2. Clear namespaced caches containing tagged items before upgrading or rolling back.
- Public hierarchy keys use a separate storage path. Clear namespaced caches containing hierarchy keys before upgrading or rolling back.
Clear a namespaced cache before upgrading or rolling back when a namespace contains bytes outside [A-Za-z0-9_.] or a lowercase _x sequence. Clear it when a public key contains |, !, or a lowercase _x sequence.
Clear a prefixed cache when its prefix contains bytes outside [A-Za-z0-9_.] or a lowercase _x sequence.
Generic PSR-6 namespace decorators persist a random generation before deriving storage keys. They probe alternate metadata keys instead of overwriting an unrelated value.
Use this deployment sequence:
- Stop or drain every old worker.
- Clear each affected APCu, Redis, Predis, namespaced, or prefixed cache.
- Deploy version 2 and restart the workers.
Use the same sequence before rolling back. No other cache formats change unless an adapter README says otherwise.
Update these client libraries before installing version 2:
- The Filesystem adapter supports Flysystem 2 and 3. It no longer supports Flysystem 1.
- The Illuminate adapter supports
illuminate/cache11 through 13. - The Predis adapter supports Predis 2 and 3. It no longer supports Predis 1.
Custom adapters that extend AbstractCachePool must add version 2's native types. Follow the custom adapter upgrade guide.
Tags¶
Tags let an app invalidate related items without knowing every cache key.
$product = $pool->getItem('product.42');
$product->set(['name' => 'Desk'])->setTags(['products', 'featured']);
$pool->save($product);
$pool->invalidateTag('products');
$pool->getItem('product.42')->isHit();
The final call returns false after invalidation. Pools and items expose tags through the interfaces in cache/tag-interop.
Hierarchical keys¶
A hierarchical key starts with |. Deleting a parent path invalidates every cached descendant.
$item = $pool->getItem('|users|42|followers|7|likes');
$item->set(12);
$pool->save($item);
$pool->deleteItem('|users|42|followers');
$pool->hasItem('|users|42|followers|7|likes');
The final call returns false. Read the hierarchy guide for details.
Namespaces and prefixes¶
NamespacedCachePool isolates one logical cache inside any PSR-6 pool. Its clear() method invalidates only that namespace.
PrefixedCachePool works with any PSR-6 pool. Its clear() method clears the entire wrapped pool. Read the namespace guide before choosing between them.
Use each decorator's create() factory when the wrapped pool supports tags. The factory preserves taggable items and forwards tag invalidation.
Chain pools¶
CachePoolChain reads through a list of PHP Cache pools and backfills earlier pools after a hit. Writes and tag invalidations run against each active pool.
The chain implements both PSR-6 and PSR-16. Each member must implement Cache\Adapter\Common\PhpCachePool so the chain can transfer items during backfills.
By default, a backend exception stops the operation. Set skip_on_failure to remove that pool from the current chain instance and continue:
composer require cache/chain-adapter:^2.1 cache/void-adapter:^3.0
use Cache\Adapter\Chain\CachePoolChain;
use Cache\Adapter\Void\VoidCachePool;
$cache = new CachePoolChain(
[$redisPool, new VoidCachePool()],
['skip_on_failure' => true],
);
$cache->setMultiple(['report' => $report], 60);
$values = $cache->getMultiple(['report', 'missing'], null);
Invalid cache keys still throw. skip_on_failure handles exceptions during cache operations, but it cannot handle a pool that fails during construction.
Adapter-specific APIs¶
MemcachedCachePool sends PSR-16 bulk calls through Memcached's native getMulti(), setMulti(), and deleteMulti() commands. Bulk writes share one expiration and remove old tag references only after storage succeeds.
FilesystemCachePool exposes its Flysystem instance and cache folder through accessors:
$pool->setFolder('tenant/cache');
$pool->setFilesystem($replacementFilesystem);
$folder = $pool->getFolder();
$filesystem = $pool->getFilesystem();
setFolder() normalizes slash styles and removes empty or current-directory segments. It rejects root and parent-directory paths. setFilesystem() creates the current cache directory on the replacement filesystem.
Filesystem Adapter 3 hashes keys into 256 shard directories by default. This avoids platform-specific filenames and large flat directories.
Subclasses can override the protected getFilePath() method for custom layouts. Custom paths must remain deterministic, portable, and below the configured cache folder. Call the parent method first to keep the default key hash. Use a dedicated cache folder because clear() removes every file below it.
Session locking¶
The PSR-6 and PSR-16 session handlers require a SessionLockInterface. Pass the lock before the options array:
use Cache\SessionHandler\Psr6SessionHandler;
$handler = new Psr6SessionHandler($pool, $sessionLock, [
'prefix' => 'session.',
'ttl' => 3600,
]);
The lock must acquire each session ID atomically across every process that shares the cache. A cache read followed by a cache write is not an atomic lock.
The handler acquires the lock during session validation or reading. It holds the lock until PHP closes or destroys the session.
CacheBundle supplies a Symfony Lock implementation. Standalone users must provide an implementation with a lease that recovers from crashed requests.
Bridges and integrations¶
The project also maintains these packages:
- PSR-6 to Doctrine Cache bridge
- PSR-6 to PSR-16 bridge
- Encrypted cache decorator
- Taggable cache decorator
- PSR cache session handlers
- Symfony AdapterBundle
- Symfony CacheBundle
Report documentation or package problems on the GitHub issue tracker.