A lightweight, PSR-16 compliant caching library for PHP 8.4+ with support for multiple storage backends.
- PSR-16 Simple Cache compliant
- Multiple drivers: Redis, Valkey, SQLite, File, APCu
- Automatic key prefixing for namespace isolation
- Type-safe with full PHP 8.4 type declarations
- Zero configuration defaults for quick setup
- Garbage collection for file-based caches
- Batch operations for improved performance
- PHP 8.4 or higher
- PDO extension (for SQLite driver)
- APCu extension (optional, for APCu driver)
- Redis/Valkey server (optional, for Redis driver)
composer require elliephp/cacheuse ElliePHP\Components\Cache\CacheFactory;
use ElliePHP\Components\Cache\Cache;
// Create a file-based cache
$driver = CacheFactory::createFileDriver([
'path' => '/path/to/cache'
]);
$cache = new Cache($driver);
// Store a value
$cache->set('user:123', 'John Doe', 3600);
// Retrieve a value
$name = $cache->get('user:123'); // "John Doe"
// Check if exists
if ($cache->has('user:123')) {
// ...
}
// Delete a value
$cache->delete('user:123');
// Clear all cache
$cache->clear();Stores cache data as JSON files on the filesystem.
$driver = CacheFactory::createFileDriver([
'path' => '/path/to/cache',
'create_directory' => true, // Auto-create directory
'directory_permissions' => 0755 // Directory permissions
]);
$cache = new Cache($driver);Garbage Collection:
// Clear expired cache files
$deletedCount = $driver->clearExpired();Uses Redis or Valkey for high-performance caching.
$driver = CacheFactory::createRedisDriver([
'host' => '127.0.0.1',
'port' => 6379,
'password' => null, // Optional
'database' => 0, // Redis database number
'timeout' => 5.0, // Connection timeout
'prefix' => 'myapp:' // Optional key prefix
]);
$cache = new Cache($driver);Stores cache in a SQLite database file.
$driver = CacheFactory::createSQLiteDriver([
'path' => '/path/to/cache.db',
'create_directory' => true,
'directory_permissions' => 0755
]);
$cache = new Cache($driver);Garbage Collection:
// Clear expired cache entries
$deletedCount = $driver->clearExpired();Uses PHP's APCu extension for in-memory caching.
$driver = CacheFactory::createApcuDriver();
$cache = new Cache($driver);// Set with TTL (in seconds)
$cache->set('key', 'value', 3600);
// Set without expiry (forever)
$cache->set('key', 'value', null);
$cache->set('key', 'value', 0);
// Get with default value
$value = $cache->get('key', 'default');
// Check existence
if ($cache->has('key')) {
// Key exists and is not expired
}
// Delete
$cache->delete('key');
// Clear all
$cache->clear();// Get multiple values
$values = $cache->getMultiple(['user:1', 'user:2', 'user:3'], 'default');
// Returns: ['user:1' => 'John', 'user:2' => 'Jane', 'user:3' => 'default']
// Set multiple values
$cache->setMultiple([
'user:1' => 'John',
'user:2' => 'Jane',
'user:3' => 'Bob'
], 3600);
// Delete multiple values
$cache->deleteMultiple(['user:1', 'user:2', 'user:3']);use DateInterval;
// Cache for 1 hour
$cache->set('key', 'value', new DateInterval('PT1H'));
// Cache for 1 day
$cache->set('key', 'value', new DateInterval('P1D'));
// Cache for 30 days
$cache->set('key', 'value', new DateInterval('P30D'));// Get total number of cached items
$count = $cache->count();
// Get total cache size in bytes
$size = $cache->size();All cache keys are automatically prefixed with ellie_cache: to prevent collisions. You don't need to worry about this - it's handled transparently.
$cache->set('user', 'John');
// Actual key stored: "ellie_cache:user"
$cache->get('user');
// Retrieves: "ellie_cache:user"Keys are validated according to PSR-16 specifications:
- Cannot be empty
- Maximum 255 characters
- Cannot contain:
{}()/\@:
try {
$cache->set('invalid{key}', 'value');
} catch (\ElliePHP\Components\Cache\Exceptions\InvalidArgumentException $e) {
// Handle invalid key
}Use the factory for dynamic driver selection:
use ElliePHP\Components\Cache\CacheFactory;
use ElliePHP\Components\Cache\CacheDrivers;
$driver = CacheFactory::create(CacheDrivers::REDIS, [
'host' => '127.0.0.1',
'port' => 6379
]);
// Or use string
$driver = CacheFactory::create('redis', [
'host' => '127.0.0.1'
]);Available driver constants:
CacheDrivers::REDIS- Redis driverCacheDrivers::VALKEY- Valkey (Redis-compatible)CacheDrivers::SQLITE- SQLite driverCacheDrivers::FILE- File driverCacheDrivers::APCU- APCu driver
use ElliePHP\Components\Cache\Exceptions\CacheException;
use ElliePHP\Components\Cache\Exceptions\InvalidArgumentException;
try {
$driver = CacheFactory::createRedisDriver([
'host' => 'invalid-host'
]);
} catch (CacheException $e) {
// Handle connection errors
echo "Cache error: " . $e->getMessage();
}
try {
$cache->set('', 'value');
} catch (InvalidArgumentException $e) {
// Handle invalid key
echo "Invalid key: " . $e->getMessage();
}- APCu: Best for single-server setups, fastest performance
- Redis/Valkey: Best for distributed systems, shared cache
- SQLite: Good for moderate traffic, persistent cache
- File: Good for development, simple deployments
// Short-lived data (5 minutes)
$cache->set('api:rate-limit', $data, 300);
// Medium-lived data (1 hour)
$cache->set('user:session', $data, 3600);
// Long-lived data (1 day)
$cache->set('config:settings', $data, 86400);
// Permanent data (until manually deleted)
$cache->set('app:version', $data, null);// Instead of multiple get() calls
$user1 = $cache->get('user:1');
$user2 = $cache->get('user:2');
$user3 = $cache->get('user:3');
// Use getMultiple()
$users = $cache->getMultiple(['user:1', 'user:2', 'user:3']);$data = $cache->get('expensive:data');
if ($data === null) {
// Cache miss - fetch from source
$data = $this->fetchExpensiveData();
// Store in cache
$cache->set('expensive:data', $data, 3600);
}
return $data;For file and SQLite drivers, schedule periodic cleanup:
// In a cron job or scheduled task
$driver->clearExpired();- Use Redis for high-traffic applications - It's the fastest for concurrent access
- Batch operations - Use
getMultiple()andsetMultiple()when possible - Set appropriate TTLs - Don't cache forever unless necessary
- Monitor cache size - Use
$cache->size()to track growth - Use key prefixes - The built-in prefix prevents collisions
# Run tests
composer test
# Run tests with coverage
composer test:coverageContributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
- Issues: GitHub Issues
- Source: GitHub Repository
Created by Joey Boli
See IMPROVEMENTS.md for recent improvements and changes.