Cache
The Cache plugin provides a PSR-16 compliant key-value caching mechanism with optional time-to-live (TTL) support.
Four adapters are available:
- InMemoryCache stores values in a PHP array with TTL support. Ideal for testing and single-request caching.
- RedisCache stores values in Redis with native TTL support and secure deserialization. Suitable for distributed caching in production environments.
- FileCache stores values as JSON files in a specified directory with TTL support. Suitable for development and simple persistence scenarios.
- NullCache implements the Null Object pattern, never storing values. Useful for disabling caching in specific environments.
PSR-16 Compatibility
The plugin implements Psr\SimpleCache\CacheInterface, making it interoperable with any PSR-16 compliant library. The CacheInterface port extends the PSR interface, allowing type-hints with either Phexium\Plugin\Cache\Port\CacheInterface or Psr\SimpleCache\CacheInterface.
Why Use It
Caching reduces redundant computation and external service calls. The plugin provides a clean interface that abstracts the storage mechanism, allowing different adapters for different environments (in-memory for tests, file-based for development, external services for production).
Usage
Basic cache operations:
$this->cache->set('user.123', $userData, 3600); // Cache for 1 hour
$user = $this->cache->get('user.123'); // Returns null if expired/missing
$this->cache->delete('user.123'); // Remove specific key
$this->cache->clear(); // Remove all cached items
Default value on cache miss:
Check existence before retrieval:
TTL behavior:
$this->cache->set('key', 'value'); // No expiration
$this->cache->set('key', 'value', 300); // Expires in 5 minutes
$this->cache->set('key', 'value', new DateInterval('P1D')); // Expires in 1 day
$this->cache->set('key', 'value', 0); // Deletes existing entry
$this->cache->set('key', 'value', -1); // Deletes existing entry
Batch operations:
// Retrieve multiple keys at once
$values = $this->cache->getMultiple(['user.1', 'user.2', 'user.3'], $default);
// Store multiple values
$this->cache->setMultiple([
'user.1' => $user1,
'user.2' => $user2,
], 3600);
// Delete multiple keys
$this->cache->deleteMultiple(['user.1', 'user.2']);
RedisCache Security
RedisCache uses PHP's unserialize() with strict class whitelisting to prevent PHP Object Injection attacks. By default, no classes are allowed for deserialization.
Allowed Classes Configuration
The second constructor parameter specifies which classes can be deserialized:
// No classes allowed (default) - objects become __PHP_Incomplete_Class
$cache = new RedisCache($redis);
// Whitelist specific classes
$cache = new RedisCache($redis, [
ListBooksResponse::class,
DetailBookResponse::class,
]);
// Allow all classes (not recommended for production)
$cache = new RedisCache($redis, true);
Container Configuration
When using RedisCache with CachedQueryBus, configure the allowed QueryResponse classes:
CacheInterface::class => fn (ContainerInterface $c): RedisCache => new RedisCache(
$c->get(Redis::class),
[
ListBooksResponse::class,
DetailBookResponse::class,
// Add all CacheableQueryInterface response classes
],
),
Any class not in the whitelist will be deserialized as __PHP_Incomplete_Class, preventing potential code execution from malicious serialized data in Redis.
Testing
Use InMemoryCache with FrozenClock to test TTL-dependent code:
Use NullCache to verify code behavior when cache misses always occur:
Use the test fake to track cache interactions:
$cache = new \Tests\Phexium\Fake\Plugin\Cache\Cache();
// ... execute code that uses cache ...
expect($cache->getCallCount('set'))->toBe(2);
expect($cache->wasMethodCalled('clear'))->toBeFalse();
See Also
- Clock - Testable time operations for TTL
- PSR-16 Simple Cache - Interface specification