API Index — Namespaces, Packages, Reports, Indices
Cache
in package
Cache — Tiered key-value cache (memory + file)
General-purpose cache with a dead-simple API. Two tiers: Tier 1: In-memory via Store (OpenSwoole\Table) — fast, cross-worker, volatile Tier 2: File-based (.cache/ directory) — persistent, survives restarts
Every set() writes through to both tiers. get() checks memory first, falls back to file. TTL-based expiry with lazy cleanup + periodic GC timer.
Usage:
// Before $app->run():
Cache::init();
// Anywhere (any worker):
Cache::set('user:42', $profile, ttl: 300);
$profile = Cache::get('user:42');
Cache::has('user:42');
Cache::del('user:42');
LIMITATIONS — when to use Redis/Valkey instead:
- Multi-server: Cache is per-server. Redis shares state across machines.
- Large datasets: Memory tier caps at maxRows (default 4096), 8KB per value.
- Pub/Sub: No built-in publish/subscribe between workers or servers.
- Data structures: No sorted sets, streams, Lua scripting. Flat KV only.
- Persistence: File tier is best-effort. Redis AOF/RDB is crash-safe.
- Eviction: No LRU/LFU. Full memory tier spills to file-only.
- Transactions: No MULTI/EXEC. Store has per-row spinlocks only.
Table of Contents
Constants
- MAX_MEM_SIZE : mixed = 8192
- STAMPEDE_LOCK_SLOTS : mixed = 256
- Fixed pool size for getOrCompute() stampede locks — bounds the backend's counter map instead of growing one lock per distinct key forever.
- TABLE : mixed = '__cache'
Properties
- $dir : string
- $fileRotations : Counter|null
- C-2: count of file-tier evictions due to maxFiles cap (oldest-first).
- $hitsFile : Counter|null
- $hitsMem : Counter|null
- $initialized : bool
- $maxFiles : int
- C-2: cap on file-tier entries — oldest-first eviction beyond this. 0 = unlimited.
- $misses : Counter|null
- $spillsFile : Counter|null
- $spillsFull : Counter|null
- $stampedeBlocked : Counter|null
- C-1: stampede gate — count of getOrCompute losers that waited then served from cache.
- $tagInvalidations : Counter|null
- C-3: count of tag invalidations performed.
Methods
- clear() : bool
- Alias for flush() — PSR-16 naming convention. Returns true.
- count() : int
- Number of entries in memory tier (may include expired).
- del() : bool
- Delete from both tiers.
- delete() : bool
- Alias for del() — PSR-16 naming convention.
- flush() : void
- Clear all cache entries from both tiers.
- get() : mixed
- Retrieve a value. Memory tier checked first, file tier as fallback.
- getOrCompute() : T
- Read-through helper: if
$keyexists, return it; otherwise call$compute(), store the result, and return it. - has() : bool
- Check existence without deserializing. Respects TTL.
- init() : void
- Initialize the cache. Must be called before $app->run().
- invalidateTag() : int
- C-3 — invalidate every key that was set() with the given tag.
- mget() : array<string, mixed>
- Batch get — fetch multiple keys in one call.
- mset() : int
- Batch set — store multiple key-value pairs in one call.
- set() : bool
- Store a value. Writes to both memory and file tiers.
- stats() : array{memory_entries: int, hits_memory: int, hits_file: int, misses: int, spills_oversize: int, spills_full: int, stampede_blocked: int, file_rotations: int, tag_invalidations: int, hit_rate: float}
- Cache performance stats. All counters are cross-worker (atomic).
- filePath() : string
- readFile() : mixed
- registerGc() : void
- writeFile() : bool
Constants
MAX_MEM_SIZE
private
mixed
MAX_MEM_SIZE
= 8192
STAMPEDE_LOCK_SLOTS
Fixed pool size for getOrCompute() stampede locks — bounds the backend's counter map instead of growing one lock per distinct key forever.
private
mixed
STAMPEDE_LOCK_SLOTS
= 256
TABLE
private
mixed
TABLE
= '__cache'
Properties
$dir
private
static string
$dir
= ''
$fileRotations
C-2: count of file-tier evictions due to maxFiles cap (oldest-first).
private
static Counter|null
$fileRotations
= null
$hitsFile
private
static Counter|null
$hitsFile
= null
$hitsMem
private
static Counter|null
$hitsMem
= null
$initialized
private
static bool
$initialized
= false
$maxFiles
C-2: cap on file-tier entries — oldest-first eviction beyond this. 0 = unlimited.
private
static int
$maxFiles
= 0
$misses
private
static Counter|null
$misses
= null
$spillsFile
private
static Counter|null
$spillsFile
= null
$spillsFull
private
static Counter|null
$spillsFull
= null
$stampedeBlocked
C-1: stampede gate — count of getOrCompute losers that waited then served from cache.
private
static Counter|null
$stampedeBlocked
= null
$tagInvalidations
C-3: count of tag invalidations performed.
private
static Counter|null
$tagInvalidations
= null
Methods
clear()
Alias for flush() — PSR-16 naming convention. Returns true.
public
static clear() : bool
Return values
boolcount()
Number of entries in memory tier (may include expired).
public
static count() : int
Return values
intdel()
Delete from both tiers.
public
static del(string $key) : bool
Parameters
- $key : string
Return values
booldelete()
Alias for del() — PSR-16 naming convention.
public
static delete(string $key) : bool
Parameters
- $key : string
Return values
boolflush()
Clear all cache entries from both tiers.
public
static flush() : void
get()
Retrieve a value. Memory tier checked first, file tier as fallback.
public
static get(string $key[, mixed $default = null ]) : mixed
Parameters
- $key : string
- $default : mixed = null
getOrCompute()
Read-through helper: if $key exists, return it; otherwise call
$compute(), store the result, and return it.
public
static getOrCompute(string $key, callable(): T $compute[, int $ttl = 0 ]) : T
The fall-through-on-miss-then-compute pattern is the canonical way to cache expensive lookups (DB queries, API calls, derived values). Without this helper users write the same 3 lines:
$v = Cache::get($k);
if ($v === null) { $v = expensiveLookup($k); Cache::set($k, $v, $ttl); }
return $v;
getOrCompute() collapses that to one call:
$v = Cache::getOrCompute($k, fn() => expensiveLookup($k), $ttl);
Storage semantics are identical to set()+get() — the value goes
to BOTH the memory tier (Store table, capped at MAX_MEM_SIZE) AND
the file tier (large values + overflow). Subsequent calls within
$ttl short-circuit to the cached read.
Parameters
- $key : string
- $compute : callable(): T
- $ttl : int = 0
Tags
Return values
Thas()
Check existence without deserializing. Respects TTL.
public
static has(string $key) : bool
Parameters
- $key : string
Return values
boolinit()
Initialize the cache. Must be called before $app->run().
public
static init([int $maxRows = 4096 ][, string|null $cacheDir = null ][, int $gcIntervalMs = 60000 ][, int|null $ttlSeconds = null ][, int $maxFiles = 0 ]) : void
Parameters
- $maxRows : int = 4096
-
Max entries in memory tier (default 4096). HARD CAP on the Table backend (OpenSwoole\Table allocates a fixed-size shared-memory segment). NOT ENFORCED on the Redis backend — Redis is a global key-value store with no per-table size cap. Pair with
$ttlSecondsOR configure Redis-servermaxmemory+maxmemory-policyfor bounded growth there. See the warning emitted at init() when this combo is misused. - $cacheDir : string|null = null
-
File tier directory (default: .cache/ in project root)
- $gcIntervalMs : int = 60000
-
GC sweep interval in ms (default 60000)
- $ttlSeconds : int|null = null
-
Per-key TTL hint (default null). On the Redis backend, setting this flips the underlying Store table to
mode='ttl'so keys auto-expire server-side (Cache::set's per-key$ttlstill wins as a per-call override; this is the DEFAULT TTL for keys whose set() doesn't pass one). - $maxFiles : int = 0
invalidateTag()
C-3 — invalidate every key that was set() with the given tag.
public
static invalidateTag(string $tag) : int
Drops the entries from both memory + file tiers in a single sweep. Returns the count of keys invalidated.
Requires Redis or Tiered backend (the tag→keys SET lives in Redis).
On Table backend this is a no-op + warns to error_log; for
single-node cache groups, prefer keying with a versioned prefix
(e.g. Cache::set("user:42:v$ver", ...) + bump $ver to invalidate).
Parameters
- $tag : string
Return values
intmget()
Batch get — fetch multiple keys in one call.
public
static mget(array<int, string> $keys) : array<string, mixed>
Returns an associative array of key => value for keys that exist. Missing keys are omitted from the result.
Parameters
- $keys : array<int, string>
Return values
array<string, mixed>mset()
Batch set — store multiple key-value pairs in one call.
public
static mset(array<string, mixed> $items[, int $ttl = 0 ]) : int
Returns the number of keys successfully stored.
Parameters
- $items : array<string, mixed>
-
key => value
- $ttl : int = 0
Return values
intset()
Store a value. Writes to both memory and file tiers.
public
static set(string $key, mixed $value[, int $ttl = 0 ][, array<int, string> $tags = [] ]) : bool
Values larger than 8KB are stored in file tier only.
Parameters
- $key : string
- $value : mixed
- $ttl : int = 0
- $tags : array<int, string> = []
-
C-3: optional tags for bulk invalidation via
Cache::invalidateTag($tag). Tag index requires Redis-capable backend (Redis / Tiered); ignored otherwise.
Return values
boolstats()
Cache performance stats. All counters are cross-worker (atomic).
public
static stats() : array{memory_entries: int, hits_memory: int, hits_file: int, misses: int, spills_oversize: int, spills_full: int, stampede_blocked: int, file_rotations: int, tag_invalidations: int, hit_rate: float}
Returns: [ 'memory_entries' => int, // current rows in memory tier 'hits_memory' => int, // get() served from memory 'hits_file' => int, // get() served from file (memory miss) 'misses' => int, // get() found nothing 'spills_oversize' => int, // set() skipped memory (value > 8KB) 'spills_full' => int, // set() skipped memory (table full) 'stampede_blocked' => int, // C-1 — getOrCompute losers that // waited then served cached 'file_rotations' => int, // C-2 — file evictions by maxFiles cap 'tag_invalidations'=> int, // C-3 — Cache::invalidateTag calls 'hit_rate' => float, // hits / (hits + misses), 0.0–1.0 ]
Return values
array{memory_entries: int, hits_memory: int, hits_file: int, misses: int, spills_oversize: int, spills_full: int, stampede_blocked: int, file_rotations: int, tag_invalidations: int, hit_rate: float}filePath()
private
static filePath(string $hash) : string
Parameters
- $hash : string
Return values
stringreadFile()
private
static readFile(string $hash) : mixed
Parameters
- $hash : string
registerGc()
private
static registerGc(int $intervalMs) : void
Parameters
- $intervalMs : int
writeFile()
private
static writeFile(string $hash, string $serialized, int $expires) : bool
Parameters
- $hash : string
- $serialized : string
- $expires : int