cash/lrucache
Memory-based, non-persistent Least Recently Used (LRU) cache for PHP. Supports integer or string keys and any value types, with a fixed max size and automatic eviction of least-recently-used entries when capacity is exceeded.
Installation:
composer require cash/lrucache
No additional configuration or service provider registration is needed.
First Use Case:
use Cash\LRUCache;
// Initialize with a max item count (e.g., 100)
$cache = new LRUCache(100);
// Store data
$cache->put('user:123', ['name' => 'John', 'premium' => true]);
// Retrieve data
$user = $cache->get('user:123'); // Returns ['name' => 'John', 'premium' => true] or null
// Check existence
if ($cache->has('user:123')) {
echo "User exists in cache!";
}
Where to Look First:
get(), put(), has(), and remove()."7" and integer keys 7 are treated as identical.Use LRUCache directly in services or controllers for non-persistent, high-speed caching:
// app/Services/UserService.php
use Cash\LRUCache;
class UserService {
protected $cache;
public function __construct() {
$this->cache = new LRUCache(1000); // Max 1000 items
}
public function getUserData($userId) {
$cacheKey = "user:$userId:data";
if ($this->cache->has($cacheKey)) {
return $this->cache->get($cacheKey);
}
// Expensive operation (e.g., DB/API call)
$data = $this->fetchFromDatabase($userId);
$this->cache->put($cacheKey, $data);
return $data;
}
}
Extend Laravel’s Cache facade to support LRUCache as a driver. Create a custom adapter:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Cache;
use Cash\LRUCache;
public function boot() {
Cache::extend('lru', function ($app) {
$maxSize = config('cache.lru.max_size', 1000);
return Cache::repository(new LRUCacheAdapter(new LRUCache($maxSize)));
});
}
// app/Adapters/LRUCacheAdapter.php
use Illuminate\Contracts\Cache\Store;
use Cash\LRUCache;
class LRUCacheAdapter implements Store {
protected $cache;
public function __construct(LRUCache $cache) {
$this->cache = $cache;
}
public function get($key) {
return $this->cache->get($key);
}
public function put($key, $value, $seconds = null) {
$this->cache->put($key, $value);
return true;
}
// Implement other Store methods (has, remove, etc.)
// ...
}
Register the driver in config/cache.php:
'lru' => [
'driver' => 'lru',
'max_size' => 1000,
],
Now use it like any other cache driver:
Cache::store('lru')->put('key', 'value', 60); // 60 ignored (no TTL)
Cache API responses or view data using middleware:
// app/Http/Middleware/CacheLRUResponse.php
use Closure;
use Cash\LRUCache;
class CacheLRUResponse {
protected $cache;
public function __construct() {
$this->cache = new LRUCache(500);
}
public function handle($request, Closure $next) {
$response = $next($request);
if (!$request->wantsJson()) {
return $response;
}
$cacheKey = 'response:'.$request->getPath();
$this->cache->put($cacheKey, $response->getContent());
return $response;
}
}
Cache expensive function results:
// app/Helpers/CacheHelper.php
use Cash\LRUCache;
$cache = new LRUCache(50);
function getExpensiveData($id) {
$cacheKey = "expensive:$id";
if ($cache->has($cacheKey)) {
return $cache->get($cacheKey);
}
$result = expensiveOperation($id);
$cache->put($cacheKey, $result);
return $result;
}
Track API request counts per user/IP:
// app/Services/RateLimiter.php
use Cash\LRUCache;
class RateLimiter {
protected $cache;
public function __construct() {
$this->cache = new LRUCache(10000); // Max 10k entries
}
public function check($key) {
$count = $this->cache->get($key, 0);
if ($count >= 100) { // Max 100 requests
return false;
}
$this->cache->put($key, $count + 1);
return true;
}
}
Key Naming Conventions:
Use namespaced keys to avoid collisions (e.g., user:123:prefs, api:product:123).
Avoid raw integers or ambiguous strings like "7" (will collide with 7).
Size Management:
max_size (e.g., 1000) and monitor memory usage.memory_get_usage() to track impact:
$cache = new LRUCache(1000);
$cache->put('key', str_repeat('x', 1024)); // ~1KB per item
echo memory_get_usage(true); // Check memory after bulk inserts
Eviction Handling:
LRUCache:
class CustomLRUCache extends LRUCache {
protected function onEvict($key) {
// Log or handle evicted keys
Log::debug("Evicted key: {$key}");
}
}
Thread Safety:
Fallback Strategy: Combine with Laravel’s default cache for persistence:
$cache = new LRUCache(100);
$fallback = Cache::store('file');
function getWithFallback($key) {
if ($cache->has($key)) {
return $cache->get($key);
}
$value = $fallback->get($key);
if ($value !== null) {
$cache->put($key, $value);
}
return $value;
}
Key Collisions:
"7" and integer keys 7 are treated as identical.
$cache = new LRUCache(2);
$cache->put("7", "string");
$cache->put(7, "integer"); // Overwrites "7"!
str:7, int:7) or avoid mixing types.Memory Leaks:
max_size is too large or not enforced.max_size and monitor memory:
$cache = new LRUCache(1000); // Hard limit
if (memory_get_usage() > 50 * 1024 * 1024) { // >50MB
throw new \RuntimeException("Cache memory limit exceeded!");
}
Non-Persistence:
$lru = new LRUCache(100);
$redis = Cache::store('redis');
function getCriticalData($key) {
if ($lru->has($key)) {
return $lru->get($key);
}
$data = $redis->get($key);
if ($data) {
$lru->put($key, $data); // Warm LRU
}
return $data
How can I help you explore Laravel packages today?