PHPackages                             joby/smol-cache - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. joby/smol-cache

ActiveLibrary[Caching](/categories/caching)

joby/smol-cache
===============

A set of simple lightweight caching implementations, and wrappers for implementing the same interfaces from common standards.

v1.2.0(2mo ago)0931MITPHPPHP &gt;=8.1CI passing

Since Jan 14Pushed 2mo agoCompare

[ Source](https://github.com/joby-lol/smol-cache)[ Packagist](https://packagist.org/packages/joby/smol-cache)[ RSS](/packages/joby-smol-cache/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (2)Versions (6)Used By (1)

smolCache
=========

[](#smolcache)

A lightweight PHP caching library with tag support and hierarchical invalidation.

Installation
------------

[](#installation)

```
composer require joby-lol/smol-cache
```

About
-----

[](#about)

smol-cache provides a simple, consistent interface for caching data with support for tags, TTL expiration, and hierarchical cache invalidation. It includes two implementations:

- **EphemeralCache**: In-memory cache for single-request caching
- **SqliteCache**: Persistent SQLite-backed cache for multi-request caching

**Hierarchical Organization**: Both keys and tags use forward slash (`/`) as the canonical delimiter for hierarchical structures, enabling powerful recursive operations.

Basic Usage
-----------

[](#basic-usage)

```
use Joby\Smol\Cache\SqliteCache;

$cache = new SqliteCache('/path/to/cache.db', ttl: 3600);

// Set a value
$cache->set('user/123', ['name' => 'Alice', 'email' => 'alice@example.com']);

// Get a value
$user = $cache->get('user/123');

// Check if exists
if ($cache->has('user/123')) {
    // ...
}

// Delete a value
$cache->delete('user/123');
```

Cache Implementations
---------------------

[](#cache-implementations)

### EphemeralCache

[](#ephemeralcache)

In-memory cache that persists only for the current request.

```
use Joby\Smol\Cache\EphemeralCache;

$cache = new EphemeralCache(ttl: 30); // 30 second default TTL
```

### SqliteCache

[](#sqlitecache)

Persistent cache backed by SQLite database.

```
use Joby\Smol\Cache\SqliteCache;

// Basic usage
$cache = new SqliteCache('/path/to/cache.db', ttl: 300);

// With automatic cleanup (1 in 100 chance on each instantiation)
$cache = new SqliteCache('/path/to/cache.db', ttl: 300, cleanup_odds: 100);
```

Core Methods
------------

[](#core-methods)

### get()

[](#get)

Retrieve a value from the cache, optionally setting a default if not found.

```
// Simple get
$value = $cache->get('key');

// Get with default
$value = $cache->get('key', 'default value');

// Get with callable default (only executed if key doesn't exist)
$value = $cache->get('expensive/calculation', function() {
    return performExpensiveCalculation();
});

// Get with custom TTL and tags
$value = $cache->get('key', 'default', ttl: 600, tags: 'user-data');
```

### set()

[](#set)

Store a value in the cache.

```
// Simple set
$cache->set('key', 'value');

// Set with custom TTL
$cache->set('key', 'value', ttl: 1800);

// Set with tags
$cache->set('key', 'value', tags: ['user', 'profile']);

// Set with callable (executed immediately and result is cached)
$cache->set('key', fn() => computeValue());
```

### has()

[](#has)

Check if a key exists and is not expired.

```
if ($cache->has('user/123')) {
    // Key exists
}
```

### delete()

[](#delete)

Remove a value from the cache. Use slash (`/`) as the delimiter for hierarchical keys.

```
// Delete single key
$cache->delete('user/123');

// Delete recursively (deletes 'user' and all keys starting with 'user/123/')
$cache->delete('user', recursive: true);
// Deletes: user/123, user/123/profile, user/123/settings, user/123/posts/1, etc.
```

Tags
----

[](#tags)

Associate cache items with tags for grouped invalidation. Tags support the same hierarchical structure as keys using slash (`/`) delimiters.

```
// Set with single tag
$cache->set('user/123', $userData, tags: 'users');

// Set with multiple tags
$cache->set('post/456', $postData, tags: ['posts', 'user/123/content']);

// Clear all items with a tag
$cache->clear('users');
$cache->clear(['users', 'posts']);
```

### Hierarchical Tags

[](#hierarchical-tags)

Use slash (`/`) separated tag names for hierarchical invalidation.

```
$cache->set('post/1', $data, tags: 'content/posts/published');
$cache->set('post/2', $data, tags: 'content/posts/draft');
$cache->set('page/1', $data, tags: 'content/pages');

// Clear only published posts
$cache->clear('content/posts/published');

// Clear all posts (published and draft) - clears all tags starting with 'content/posts/'
$cache->clear('content/posts', recursive: true);

// Clear all content - clears all tags starting with 'content/'
$cache->clear('content', recursive: true);
```

Namespacing
-----------

[](#namespacing)

Create namespaced cache instances that automatically prefix keys with a namespace followed by a slash (`/`).

```
// Create namespaced cache
$userCache = $cache->namespace('user/123');

// Keys are automatically prefixed with 'user/123/'
$userCache->set('profile', $data);
// Actually sets 'user/123/profile'

$userCache->get('settings');
// Actually gets 'user/123/settings'
```

### Namespace with Default Tags and TTL

[](#namespace-with-default-tags-and-ttl)

```
// Namespace with tags that apply to all items
$userCache = $cache->namespace('user/123', tags: 'user-data', ttl: 600);

$userCache->set('profile', $data);
// Sets with both 'user-data' tag and 600 second TTL

// Clear all data for this user
$cache->clear('user-data');
```

### Nested Namespaces

[](#nested-namespaces)

Namespaces compose naturally with slash delimiters:

```
$userCache = $cache->namespace('user/123');
$settingsCache = $userCache->namespace('settings');

$settingsCache->set('theme', 'dark');
// Actually sets 'user/123/settings/theme'
```

Utility Methods
---------------

[](#utility-methods)

These are not included in the interface, but are available in the built-in implementations.

### flush()

[](#flush)

Delete all items from the cache.

```
$cache->flush();
```

### clean() (SqliteCache only)

[](#clean-sqlitecache-only)

Remove expired items from the database.

```
$cache->clean();
```

### compact() (SqliteCache only)

[](#compact-sqlitecache-only)

Reclaim unused space in the SQLite database. This operation is slow and locks the database.

```
$cache->compact();
```

Advanced Features
-----------------

[](#advanced-features)

### Callable Values and Defaults

[](#callable-values-and-defaults)

Both `get()` and `set()` accept callables, which are executed and their return value is cached.

```
// Get or compute and cache
$result = $cache->get('expensive/operation', doExpensiveOperation(...));

// Set with callable
$cache->set('timestamp', time(...));
```

### Complex Data Types

[](#complex-data-types)

All data is JSON-encoded internally, supporting arrays, objects, and scalar types. EphemeralCache does no manipulation of values, and supports literally anything that can be put in a PHP variable.

```
$cache->set('complex', [
    'user' => ['id' => 123, 'name' => 'Alice'],
    'metadata' => ['created' => time()],
    'flags' => ['active' => true, 'verified' => false]
]);

$data = $cache->get('complex');
// Returns the full array structure
```

### Hierarchical Keys

[](#hierarchical-keys)

Use slash (`/`) separators in keys for logical grouping with recursive deletion.

```
$cache->set('user/123/profile', $profile);
$cache->set('user/123/settings', $settings);
$cache->set('user/123/posts/1', $post1);
$cache->set('user/123/posts/2', $post2);

// Delete all user data - deletes all keys starting with 'user/123/'
$cache->delete('user/123', recursive: true);
```

Usage Patterns
--------------

[](#usage-patterns)

### Page Fragment Caching

[](#page-fragment-caching)

```
$cache = new SqliteCache('cache.db', ttl: 3600);

$content = $cache->get("page/$pageId/fragment/sidebar", function() use ($pageId) {
    return renderSidebar($pageId);
}, tags: "page/$pageId");

// Invalidate all fragments for a page
$cache->clear("page/$pageId");
```

### API Response Caching

[](#api-response-caching)

```
$apiCache = $cache->namespace('api/v1', ttl: 300);

$users = $apiCache->get("users/$userId", function() use ($userId) {
    return fetchUserFromDatabase($userId);
}, tags: ['users', "user/$userId"]);

// Invalidate all user data
$cache->clear('users');
```

### Computed Value Caching

[](#computed-value-caching)

```
$result = $cache->get('report/monthly', function() {
    return generateMonthlyReport();
}, ttl: 86400, tags: 'reports');

// Invalidate all reports
$cache->clear('reports');
```

Performance Considerations
--------------------------

[](#performance-considerations)

### SqliteCache Automatic Cleanup

[](#sqlitecache-automatic-cleanup)

Configure automatic cleanup to periodically remove expired entries:

```
// 1 in 100 chance of cleanup on each instantiation
$cache = new SqliteCache('cache.db', ttl: 3600, cleanup_odds: 100);
```

### Manual Cleanup

[](#manual-cleanup)

For cron-based cleanup:

```
$cache = new SqliteCache('cache.db');
$cache->clean();     // Remove expired items
$cache->compact();   // Reclaim disk space (optional, slow, locking)
```

Requirements
------------

[](#requirements)

Fully tested on PHP 8.3+, static analysis for PHP 8.1+.

License
-------

[](#license)

MIT License - See [LICENSE](LICENSE) file for details.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance83

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community5

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~9 days

Total

5

Last Release

87d ago

PHP version history (2 changes)v1.0.0PHP &gt;=8.3

v1.1.1PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/f4e606aa41ebfd7d82c365c6dc4ec158fb1b0bfff5f8dcbfad4ab53e3092e6a6?d=identicon)[jobyone](/maintainers/jobyone)

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/joby-smol-cache/health.svg)

```
[![Health](https://phpackages.com/badges/joby-smol-cache/health.svg)](https://phpackages.com/packages/joby-smol-cache)
```

###  Alternatives

[react/cache

Async, Promise-based cache interface for ReactPHP

444112.4M40](/packages/react-cache)[wp-media/wp-rocket

Performance optimization plugin for WordPress

7431.3M3](/packages/wp-media-wp-rocket)[illuminate/cache

The Illuminate Cache package.

12835.6M1.4k](/packages/illuminate-cache)[colinmollenhour/php-redis-session-abstract

A Redis-based session handler with optimistic locking

6325.6M14](/packages/colinmollenhour-php-redis-session-abstract)[cheprasov/php-redis-client

Php client for Redis. It is a fast, fully-functional and user-friendly client for Redis, optimized for performance. RedisClient supports the latest versions of Redis starting from 2.6 to 6.0

1281.2M21](/packages/cheprasov-php-redis-client)[amphp/redis

Efficient asynchronous communication with Redis servers, enabling scalable and responsive data storage and retrieval.

165634.7k44](/packages/amphp-redis)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
