Overview
The Lyger Cache system provides in-memory caching with TTL support, designed to maintain persistent state across requests without external dependencies like Redis. Built using Rust FFI for high performance.
Class: Lyger\Cache\Cache
Singleton cache manager with automatic expiration handling.
Getting Instance
use Lyger\Cache\Cache;
$cache = Cache::getInstance();
The Cache class uses the Singleton pattern. Always use getInstance() to get the instance.
Basic Operations
put()
Stores a value in the cache with optional TTL.
Value to store (any serializable type)
Time to live in seconds. Uses default TTL if null.
public function put(string $key, mixed $value, ?int $ttl = null): void
Examples:
$cache = Cache::getInstance();
// Store for default TTL (3600 seconds)
$cache->put('user:123', $userData);
// Store for 5 minutes
$cache->put('session:abc', $sessionData, 300);
// Store complex data
$cache->put('config', [
'api_key' => 'xxx',
'settings' => ['theme' => 'dark'],
], 7200);
get()
Retrieves a value from the cache.
Default value if key doesn’t exist or is expired
public function get(string $key, mixed $default = null): mixed
Examples:
// Get user data or null
$user = $cache->get('user:123');
// Get with default value
$config = $cache->get('config', ['default' => 'value']);
// Check and use
if ($data = $cache->get('expensive-query')) {
return $data;
}
has()
Checks if a key exists and is not expired.
True if key exists and is not expired
public function has(string $key): bool
Example:
if ($cache->has('user:123')) {
$user = $cache->get('user:123');
} else {
$user = fetchUserFromDatabase(123);
$cache->put('user:123', $user, 600);
}
forget()
Removes a key from the cache.
public function forget(string $key): void
Example:
// Update user and invalidate cache
updateUser($userId, $data);
$cache->forget("user:{$userId}");
flush()
Clears all cached data.
public function flush(): void
Example:
// Clear all cache
$cache->flush();
Use flush() carefully in production as it removes all cached data.
TTL Management
setTtl()
Sets the default TTL for subsequent operations.
Returns self for method chaining
public function setTtl(int $ttl): self
Example:
// Set default TTL to 10 minutes
$cache->setTtl(600);
// Subsequent puts use this TTL
$cache->put('key1', 'value1'); // Expires in 600 seconds
$cache->put('key2', 'value2'); // Expires in 600 seconds
// Override default TTL for specific key
$cache->put('key3', 'value3', 1800); // Expires in 1800 seconds
Atomic Operations
increment()
Increments a numeric value atomically.
Amount to increment (default: 1)
New value after increment
public function increment(string $key, int $value = 1): int
Example:
// Page view counter
$views = $cache->increment('page:views'); // 1
$views = $cache->increment('page:views'); // 2
$views = $cache->increment('page:views', 5); // 7
decrement()
Decrements a numeric value atomically.
Amount to decrement (default: 1)
New value after decrement
public function decrement(string $key, int $value = 1): int
Example:
// Countdown timer
$remaining = $cache->put('tickets:available', 100);
$remaining = $cache->decrement('tickets:available'); // 99
$remaining = $cache->decrement('tickets:available', 10); // 89
Remember Pattern
remember()
Gets cached value or stores result of callback if not exists.
Function to call if cache misses
public function remember(string $key, callable $callback, ?int $ttl = null): mixed
Example:
// Cache expensive database query
$users = $cache->remember('active-users', function() {
return User::where('active', true)->get();
}, 600);
// Cache API response
$weather = $cache->remember('weather:london', function() {
return file_get_contents('https://api.weather.com/london');
}, 1800);
rememberForever()
Like remember() but caches indefinitely.
Function to call if cache misses
public function rememberForever(string $key, callable $callback): mixed
Example:
// Cache configuration that rarely changes
$config = $cache->rememberForever('app-config', function() {
return loadConfigFromFile();
});
Batch Operations
getMultiple()
Gets multiple values at once.
Default value for missing keys
Associative array of key => value pairs
public function getMultiple(array $keys, mixed $default = null): array
Example:
$data = $cache->getMultiple([
'user:123',
'user:456',
'user:789',
], null);
// Returns:
// [
// 'user:123' => ['name' => 'John'],
// 'user:456' => null, // Not found
// 'user:789' => ['name' => 'Jane'],
// ]
putMultiple()
Stores multiple key-value pairs at once.
Associative array of key => value pairs
Time to live for all values
public function putMultiple(array $values, ?int $ttl = null): void
Example:
$cache->putMultiple([
'user:123' => $user123Data,
'user:456' => $user456Data,
'user:789' => $user789Data,
], 600);
Locking
lock()
Executes a callback with a distributed lock.
Function to execute while locked
Lock timeout in seconds (default: 10)
Callback result or null if lock couldn’t be acquired
public function lock(string $key, callable $callback, int $seconds = 10): mixed
Example:
// Ensure only one process updates the cache
$result = $cache->lock('update-stats', function() use ($cache) {
$stats = calculateExpensiveStats();
$cache->put('stats', $stats);
return $stats;
}, 30);
if ($result === null) {
// Another process holds the lock
echo "Update in progress...";
}
Lock Use Cases:
Prevent Race Conditions
Cache Warming
Singleton Task
// Ensure atomic counter update
$cache->lock('process-order', function() use ($orderId, $cache) {
$count = $cache->get('orders:processed', 0);
processOrder($orderId);
$cache->put('orders:processed', $count + 1);
});
// Only one server rebuilds cache
$cache->lock('warm-cache', function() use ($cache) {
$data = fetchAllProducts();
$cache->put('products', $data, 3600);
}, 60);
// Run cleanup only once
$cache->lock('daily-cleanup', function() {
cleanupOldFiles();
cleanupExpiredSessions();
}, 300);
Inspection
all()
Gets all non-expired cache entries.
Array of all cached values (excludes expired entries)
public function all(): array
Example:
$allCached = $cache->all();
// Returns: ['key1' => 'value1', 'key2' => 'value2', ...]
count()
Gets total number of cache entries (including expired).
public function count(): int
Example:
echo "Cache entries: " . $cache->count();
Practical Examples
User Session Caching
use Lyger\Cache\Cache;
class SessionManager
{
private Cache $cache;
public function __construct()
{
$this->cache = Cache::getInstance();
}
public function createSession(string $userId): string
{
$sessionId = bin2hex(random_bytes(16));
$this->cache->put("session:{$sessionId}", [
'user_id' => $userId,
'created_at' => time(),
'last_activity' => time(),
], 3600); // 1 hour
return $sessionId;
}
public function getSession(string $sessionId): ?array
{
return $this->cache->get("session:{$sessionId}");
}
public function refreshSession(string $sessionId): void
{
if ($session = $this->getSession($sessionId)) {
$session['last_activity'] = time();
$this->cache->put("session:{$sessionId}", $session, 3600);
}
}
public function destroySession(string $sessionId): void
{
$this->cache->forget("session:{$sessionId}");
}
}
Rate Limiting
class RateLimiter
{
private Cache $cache;
private int $maxAttempts = 5;
private int $decayMinutes = 1;
public function __construct()
{
$this->cache = Cache::getInstance();
}
public function tooManyAttempts(string $key): bool
{
$attempts = $this->cache->get($key, 0);
return $attempts >= $this->maxAttempts;
}
public function hit(string $key): int
{
return $this->cache->increment($key);
}
public function resetAttempts(string $key): void
{
$this->cache->forget($key);
}
public function attemptsLeft(string $key): int
{
$attempts = $this->cache->get($key, 0);
return max(0, $this->maxAttempts - $attempts);
}
}
// Usage
$limiter = new RateLimiter();
$userKey = "rate-limit:user:{$userId}";
if ($limiter->tooManyAttempts($userKey)) {
return response('Too many requests', 429);
}
$limiter->hit($userKey);
// Process request...
Query Result Caching
class ProductRepository
{
private Cache $cache;
public function __construct()
{
$this->cache = Cache::getInstance();
}
public function getFeatured(): array
{
return $this->cache->remember(
'products:featured',
fn() => $this->fetchFeaturedFromDb(),
600
);
}
public function getById(int $id): ?array
{
return $this->cache->remember(
"product:{$id}",
fn() => $this->fetchProductFromDb($id),
3600
);
}
public function update(int $id, array $data): void
{
$this->updateProductInDb($id, $data);
// Invalidate caches
$this->cache->forget("product:{$id}");
$this->cache->forget('products:featured');
}
private function fetchFeaturedFromDb(): array
{
// Database query...
return [];
}
private function fetchProductFromDb(int $id): ?array
{
// Database query...
return null;
}
private function updateProductInDb(int $id, array $data): void
{
// Database update...
}
}
API Response Caching
class WeatherService
{
private Cache $cache;
public function __construct()
{
$this->cache = Cache::getInstance();
}
public function getCurrentWeather(string $city): array
{
$cacheKey = "weather:{$city}";
return $this->cache->remember($cacheKey, function() use ($city) {
// Expensive API call
$response = file_get_contents(
"https://api.weather.com/current?city=" . urlencode($city)
);
return json_decode($response, true);
}, 1800); // Cache for 30 minutes
}
}
The Cache system automatically handles expiration. Expired entries are automatically removed when accessed via get(), has(), or all().