Skip to content
Ray Fung edited this page Feb 26, 2026 · 3 revisions

Cache System

Razy provides a PSR-16 compatible caching layer with a static facade, pluggable storage adapters, and file-validation support. The Cache system supports File, Redis, APCu, and Null adapters out of the box.


Table of Contents


Quick Start

use Razy\Cache;
use Razy\Cache\FileAdapter;

// Initialize with file adapter
Cache::initialize('/path/to/cache', new FileAdapter('/path/to/cache'));

// Store and retrieve values
Cache::set('user.profile.123', $userData, ttl: 3600);
$profile = Cache::get('user.profile.123');

// Check existence
if (Cache::has('user.profile.123')) {
    // cached
}

// Delete
Cache::delete('user.profile.123');

Initialization

The Cache facade must be initialized before use. If not initialized, it auto-initializes with a NullAdapter (no-op):

use Razy\Cache;
use Razy\Cache\FileAdapter;
use Razy\Cache\RedisAdapter;

// File-based cache
Cache::initialize('/var/cache/razy', new FileAdapter('/var/cache/razy'));

// Redis-based cache
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
Cache::initialize('', new RedisAdapter($redis, 'myapp_'));

// Check status
Cache::isInitialized(); // true

// Enable/disable at runtime (disabled = NullAdapter behavior)
Cache::setEnabled(false);
Cache::isEnabled(); // false

// Swap adapter at runtime
Cache::setAdapter(new RedisAdapter($redis));

// Get current adapter
$adapter = Cache::getAdapter();

Basic Operations

All operations follow the PSR-16 SimpleCacheInterface contract:

use Razy\Cache;

// SET ??store a value with optional TTL
Cache::set('key', 'value');                    // no expiry
Cache::set('key', 'value', 3600);              // expires in 1 hour (seconds)
Cache::set('key', 'value', new DateInterval('PT1H')); // DateInterval TTL

// GET ??retrieve with optional default
$value = Cache::get('key');                    // returns null if missing
$value = Cache::get('key', 'fallback');        // returns 'fallback' if missing

// HAS ??check existence
if (Cache::has('key')) {
    // ...
}

// DELETE ??remove a single entry
Cache::delete('key');

// CLEAR ??remove all entries
Cache::clear();

Batch Operations

Efficiently read/write multiple keys in a single call:

// SET multiple values
Cache::setMultiple([
    'user.1' => $user1,
    'user.2' => $user2,
    'user.3' => $user3,
], ttl: 3600);

// GET multiple values
$users = Cache::getMultiple(['user.1', 'user.2', 'user.3']);
// Returns: ['user.1' => $user1, 'user.2' => $user2, 'user.3' => $user3]

// GET with default for missing keys
$users = Cache::getMultiple(['user.1', 'user.999'], default: null);
// Returns: ['user.1' => $user1, 'user.999' => null]

// DELETE multiple
Cache::deleteMultiple(['user.1', 'user.2']);

File-Validated Cache

A unique Razy feature that ties cached data to a source file's modification time. If the file changes, the cache is automatically invalidated:

// Cache compiled template ??auto-invalidates when template.html changes
Cache::setValidated(
    key: 'template.compiled.main',
    filePath: '/path/to/template.html',
    data: $compiledTemplate,
    ttl: 86400
);

// Retrieve ??returns null if file has been modified since caching
$compiled = Cache::getValidated(
    key: 'template.compiled.main',
    filePath: '/path/to/template.html'
);

if ($compiled === null) {
    // File changed or cache expired ??recompile
    $compiled = compileTemplate('/path/to/template.html');
    Cache::setValidated('template.compiled.main', '/path/to/template.html', $compiled);
}

How it works: setValidated() stores the file's mtime alongside the cached data. getValidated() compares the stored mtime with the current file's mtime ??if they differ, the cache entry is considered stale and returns $default.


Adapters

FileAdapter

Directory-sharded file cache with atomic writes. Files are stored as {dir}/{xx}/{md5}.cache:

use Razy\Cache\FileAdapter;

$adapter = new FileAdapter('/var/cache/razy');

// All PSR-16 methods available
$adapter->set('key', 'value', 3600);
$value = $adapter->get('key');

// File-specific extras
$stats = $adapter->getStats();
// Returns: ['directory' => '/var/cache/razy', 'files' => 142, 'size' => 1048576]

// Garbage collection ??removes expired entries, returns count removed
$removed = $adapter->gc();

Features:

  • Atomic writes via temp file + rename (crash-safe)
  • Two-character directory sharding (e.g. ab/abcdef123456.cache)
  • Lazy purge on read (expired entries deleted when accessed)
  • Windows-compatible file handling
  • Key validation rejects PSR-16 reserved characters: {}()/\@:

RedisAdapter

High-performance Redis-backed cache:

use Razy\Cache\RedisAdapter;

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('password');
$redis->select(2);

$adapter = new RedisAdapter($redis, prefix: 'myapp_');

// Access underlying Redis instance
$redis = $adapter->getRedis();

Features:

  • Configurable key prefix (default: 'razy_')
  • serialize/unserialize for complex PHP values
  • Batch getMultiple uses Redis MGET for efficiency
  • clear() with prefix uses SCAN to delete only prefixed keys (safe for shared Redis)

ApcuAdapter

Shared memory cache via APCu extension:

use Razy\Cache\ApcuAdapter;

// Requires ext-apcu
$adapter = new ApcuAdapter(prefix: 'myapp_');

Features:

  • High performance (shared memory, no I/O)
  • clear() uses APCuIterator with prefix regex to only clear own entries
  • Best for single-server deployments

NullAdapter

No-op adapter for testing or disabled cache mode:

use Razy\Cache\NullAdapter;

$adapter = new NullAdapter();
$adapter->get('key');     // always returns default
$adapter->set('key', 1);  // always returns true
$adapter->has('key');      // always returns false

Graceful Degradation

All Cache facade operations wrap adapter calls in try/catch(\Throwable). If an adapter throws (e.g. Redis connection lost), the operation fails silently and returns the default/false:

// Even if Redis is down, this won't crash your application
$value = Cache::get('key', 'fallback'); // returns 'fallback'
Cache::set('key', 'value');             // returns false

When the cache is disabled via Cache::setEnabled(false), all operations behave as if using the NullAdapter.


API Reference

Cache Facade (Static)

Method Signature Description
initialize (string $cacheDir, ?CacheInterface $adapter): void Set up cache system
isInitialized (): bool Check if initialized
setEnabled (bool $enabled): void Enable/disable caching
isEnabled (): bool Check if enabled
getAdapter (): CacheInterface Get current adapter
setAdapter (CacheInterface $adapter): void Swap adapter
get (string $key, mixed $default = null): mixed Retrieve value
set (string $key, mixed $value, int|DateInterval|null $ttl = null): bool Store value
delete (string $key): bool Remove entry
clear (): bool Remove all entries
has (string $key): bool Check existence
getMultiple (iterable $keys, mixed $default = null): iterable Batch retrieve
setMultiple (iterable $values, int|DateInterval|null $ttl = null): bool Batch store
deleteMultiple (iterable $keys): bool Batch remove
getValidated (string $key, string $filePath, mixed $default = null): mixed File-validated get
setValidated (string $key, string $filePath, mixed $data, int|DateInterval|null $ttl = null): bool File-validated set
reset (): void Reset facade state

FileAdapter Extras

Method Signature Description
getStats (): array{directory, files, size} Cache directory statistics
gc (): int Garbage collect expired entries

??Previous: Collection Validation

Clone this wiki locally