Skip to main content

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.
key
string
required
Cache key
value
mixed
required
Value to store (any serializable type)
ttl
int|null
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.
key
string
required
Cache key
default
mixed
Default value if key doesn’t exist or is expired
return
mixed
Cached value or default
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.
key
string
required
Cache key to check
return
bool
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.
key
string
required
Cache key to remove
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.
ttl
int
required
Default TTL in seconds
return
Cache
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.
key
string
required
Cache key
value
int
Amount to increment (default: 1)
return
int
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.
key
string
required
Cache key
value
int
Amount to decrement (default: 1)
return
int
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.
key
string
required
Cache key
callback
callable
required
Function to call if cache misses
ttl
int|null
Time to live in seconds
return
mixed
Cached or computed value
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.
key
string
required
Cache key
callback
callable
required
Function to call if cache misses
return
mixed
Cached or computed value
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.
keys
array
required
Array of cache keys
default
mixed
Default value for missing keys
return
array
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.
values
array
required
Associative array of key => value pairs
ttl
int|null
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.
key
string
required
Lock key
callback
callable
required
Function to execute while locked
seconds
int
Lock timeout in seconds (default: 10)
return
mixed
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:
// 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);
});

Inspection

all()

Gets all non-expired cache entries.
return
array
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).
return
int
Number of entries
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().