Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

In Memory Cache Laravel Package

beste/in-memory-cache

PSR-6 in-memory cache for PHP, ideal as a default cache or for tests. Lightweight CacheItemPool implementation with support for expiration and optional PSR-20 clock injection (e.g., frozen clocks) to control time in tests.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require beste/in-memory-cache
    
  2. Basic Usage:

    use Beste\Cache\InMemoryCache;
    
    $cache = new InMemoryCache();
    $item = $cache->getItem('test_key');
    $item->set('test_value')->expiresAfter(60); // 60 seconds TTL
    $cache->save($item);
    
    // Retrieve later
    $hitItem = $cache->getItem('test_key');
    if ($hitItem->isHit()) {
        echo $hitItem->get(); // 'test_value'
    }
    
  3. Laravel Integration: Add to config/cache.php under stores:

    'in_memory' => [
        'driver' => 'cache',
        'store' => Beste\Cache\InMemoryCache::class,
    ],
    

    Then use in .env for testing:

    CACHE_DRIVER=in_memory
    

First Use Case

Testing Cache-Dependent Logic: Replace Redis/Memcached in unit tests with deterministic in-memory cache:

public function testCacheBehavior()
{
    $cache = new InMemoryCache();
    $cache->save($cache->getItem('user:1')->set(['name' => 'John']));

    $this->assertEquals(['name' => 'John'], $cache->getItem('user:1')->get());
}

Implementation Patterns

Core Workflows

  1. Testing Workflow:

    • Unit Tests: Use InMemoryCache directly for isolated cache assertions.
    • Integration Tests: Configure Laravel’s Cache facade to use in_memory driver via .env:
      CACHE_DRIVER=in-memory
      
    • Frozen Time Testing: Combine with beste/clock for TTL validation:
      use Beste\Clock\FrozenClock;
      
      $clock = FrozenClock::fromUTC();
      $cache = new InMemoryCache($clock);
      
      $item = $cache->getItem('time_test');
      $item->set('value')->expiresAfter(new DateInterval('PT1H'));
      $cache->save($item);
      
      $clock->setTo($clock->now()->add(new DateInterval('PT2H')));
      $this->assertFalse($cache->getItem('time_test')->isHit());
      
  2. Production Fallback:

    • Configure as a secondary driver in config/cache.php:
      'stores' => [
          'in_memory' => [
              'driver' => 'cache',
              'store' => Beste\Cache\InMemoryCache::class,
              'as' => 'fallback', // Custom alias
          ],
      ],
      
    • Use in middleware/fallback logic:
      try {
          return Cache::get('key');
      } catch (CacheException $e) {
          return Cache::store('fallback')->get('key');
      }
      
  3. Local Development:

    • Override CACHE_DRIVER in .env:
      CACHE_DRIVER=in-memory
      
    • Ideal for non-persistent, short-lived data (e.g., local dev sessions, transient metrics).

Integration Tips

  • Laravel Cache Facade: Use Cache::store('in_memory') for explicit driver selection:

    Cache::store('in_memory')->put('temp_key', 'temp_value', now()->addMinutes(5));
    
  • Tagging Support: Extend the cache to support Laravel’s tagging system by wrapping the store:

    use Illuminate\Cache\TaggingStore;
    
    $cache = new TaggingStore(new InMemoryCache());
    $cache->tags(['users'])->put('user:1', ['name' => 'John']);
    
  • Event Listeners: Leverage PSR-6’s save()/delete() events for custom logic:

    $cache->save($item); // Triggers cache events
    
  • Dependency Injection: Bind the cache in Laravel’s service container:

    $app->bind(Beste\Cache\InMemoryCache::class, function () {
        return new InMemoryCache();
    });
    

Gotchas and Tips

Pitfalls

  1. Memory Leaks:

    • Issue: Unbounded growth if items lack TTLs or are manually cleared.
    • Fix: Always set TTLs (expiresAfter()) or manually clear the cache:
      $cache->clear(); // Clears all items
      
  2. Thread/Process Safety:

    • Issue: Not thread-safe; unsafe in multi-threaded environments (e.g., Swoole).
    • Fix: Scope to single requests/processes. Avoid in long-running workers/queues without manual cleanup.
  3. Serialization Limits:

    • Issue: Fails on non-serializable objects (e.g., closures, resources).
    • Fix: Use Laravel’s serialize() helper or implement __serialize()/__unserialize():
      $item->set(serialize($complexObject));
      $data = $item->get();
      $object = unserialize($data);
      
  4. Key Validation:

    • Issue: Keys with unsupported characters (e.g., spaces, +) may fail silently.
    • Fix: Sanitize keys or use Laravel’s Str::slug():
      $key = Str::slug('user profile');
      
  5. TTL Precision:

    • Issue: Default clock uses system time, which may drift in tests.
    • Fix: Use Beste\Clock\FrozenClock for deterministic TTL testing.

Debugging

  • Inspect Cache Contents:
    $items = [];
    foreach ($cache->getMetadata('*') as $key => $metadata) {
        $items[$key] = $cache->getItem($key)->get();
    }
    
  • Check Expiry:
    $item = $cache->getItem('key');
    $expiry = $item->getExpiration();
    

Configuration Quirks

  • Clock Dependency:

    • The cache accepts an optional PSR-20 clock. Omit it for default system time:
      $cache = new InMemoryCache(); // Uses system clock
      
    • Pass a custom clock for testing:
      $cache = new InMemoryCache(new FrozenClock());
      
  • Laravel Cache Driver:

    • Ensure the driver is registered in config/cache.php:
      'stores' => [
          'in_memory' => [
              'driver' => 'cache',
              'store' => Beste\Cache\InMemoryCache::class,
          ],
      ],
      

Extension Points

  1. Custom Metadata: Extend the cache to store additional metadata:

    $item->setMetadata(['source' => 'api']);
    $metadata = $item->getMetadata();
    
  2. Event Dispatching: Wrap the cache to dispatch events (e.g., CacheStored, CacheMissed):

    $cache = new EventDispatchingCache(new InMemoryCache());
    
  3. Hybrid Cache: Combine with other stores (e.g., fallback to Redis):

    $cache = new HybridCache(new InMemoryCache(), new RedisCache());
    
  4. Size Limits: Implement a custom eviction policy (e.g., LRU) by extending InMemoryCache:

    class LimitedInMemoryCache extends InMemoryCache {
        public function __construct(int $maxItems = 1000) {
            parent::__construct();
            $this->maxItems = $maxItems;
        }
    
        public function save(ItemInterface $item): bool {
            if ($this->count() >= $this->maxItems) {
                $this->clear(); // Or implement LRU
            }
            return parent::save($item);
        }
    }
    

Performance Tips

  • Avoid Large Objects: Cache serialized data instead of large objects to reduce memory usage.
  • Use Short TTLs: Set aggressive TTLs (e.g., 1–5 minutes) to limit memory growth.
  • Clear Unused Items: Manually clear the cache in long-running processes:
    if ($cache->count() > 1000) {
        $cache->clear();
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/graphviz
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata