cache / chain-adapter
A PSR-6 and PSR-16 cache implementation using a chain of cache pools
Requires
- php: ^8.2
- cache/adapter-common: ^2.0
- cache/simple-cache-bridge: ^2.0
- cache/tag-interop: ^2.0
- psr/cache: ^3.0
- psr/log: ^3.0
- psr/simple-cache: ^2.0 || ^3.0
Requires (Dev)
- cache/array-adapter: ^2.0
- cache/filesystem-adapter: ^2.0
- cache/integration-tests: ^1.0@dev
- phpunit/phpunit: ^11.5
Suggests
- cache/void-adapter: Provides a no-op final fallback for failed cache backends
Provides
- psr/cache-implementation: 3.0
- psr/simple-cache-implementation: 2.0 || 3.0
README
This package combines multiple PHP Cache pools into one pool. CachePoolChain implements PSR-6 and PSR-16.
Reads use the first available value. Writes update each configured pool.
Installation
composer require cache/chain-adapter:^2.0
Usage
use Cache\Adapter\Apcu\ApcuCachePool; use Cache\Adapter\Chain\CachePoolChain; use Cache\Adapter\Redis\RedisCachePool; $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $pool = new CachePoolChain([ new ApcuCachePool(), new RedisCachePool($redis), ]); $pool->set('key', 'value', 60); $value = $pool->get('key');
Each pool in the chain must implement Cache\Adapter\Common\PhpCachePool. This keeps cache items transferable while the chain backfills earlier pools. Wrap the completed chain with other PSR-6 decorators instead of adding generic or decorated pools as chain members.
A key must be accepted by every pool in the chain. The chain checks each member before returning a higher-priority hit or starting a write or delete, which prevents partial mutations when one backend has narrower key rules.
Backfills preserve the cached value, expiration, and stored tags. Tag invalidation therefore removes copies from every tier.
Fallback behavior
By default, the chain throws exceptions from a pool. Set skip_on_failure to remove the failed pool and continue the operation.
Install the optional no-op pool when failures must become cache misses:
composer require cache/void-adapter:^2.0
use Cache\Adapter\Chain\CachePoolChain; use Cache\Adapter\Void\VoidCachePool; $pool = new CachePoolChain( [$redisPool, new VoidCachePool()], ['skip_on_failure' => true], );
The chain removes the failed pool for the life of that CachePoolChain instance. A configured logger receives a warning with the exception.
Raw exceptions from backend operations use the same fallback. Invalid cache keys always throw and never remove a pool.
If every member throws before one completes the operation, the chain throws NoPoolAvailableException. skip_on_failure does not convert a fully unavailable chain into a miss or false result.
Add VoidCachePool last when cache failures must become misses. Writes still run against every active pool, including VoidCachePool.
The chain cannot catch an exception thrown before the pool reaches the chain constructor. Delay backend connections until a cache operation when possible.
Contributing
Send pull requests to the main repository. Report issues on the GitHub issue tracker.