API Index — Namespaces, Packages, Reports, Indices
RedisBackend
in package
implements
StoreBackend
Redis/Valkey-backed StoreBackend.
Row layout: HASH at {prefix}:{table}:{key} (columns → hash fields).
Membership (tracked mode): SET at {prefix}:{table}:__keys__.
Two modes chosen at make():
'tracked'(default) — SET-backed;count()is O(1) viaSCARD,iterate()viaSSCAN. No TTL (an expired key cannot fireSREMon the membership set, which would drift).'ttl'— per-key expiry viaEXPIRE;count()/iterate()useSCAN MATCH(O(N)) because tracked membership isn't viable. Pick one per table; the trade-off is documented inCLAUDE.md.
Every op goes through RedisConnectionPool::with() so concurrent
coroutines never share a socket.
Table of Contents
Interfaces
- StoreBackend
- Behavioural contract every Store backend implements.
Properties
- $codec : TypeCodec
- Encodes/decodes PHP scalars to/from Redis hash field strings.
- $pool : RedisConnectionPool
- $prefix : string
- $schemas : array<string, array<string, array{0: int, 1?: int}>>
- Per-table column schemas:
table name → column name → [TYPE, size?]. - $tableOpts : array<string, array{mode: string, ttl: int}>
- Per-table options:
table name → ['mode' => 'tracked'|'ttl', 'ttl' => int].
Methods
- __construct() : mixed
- clear() : void
- Delete every row in the named table.
- count() : int
- Return the number of rows in the named table.
- decr() : int|float
- Atomically decrement a numeric column — delegates to
incr()with-$by. - del() : bool
- Delete a row from the named table.
- eval() : mixed
- Run a Lua script server-side (atomic). KEYS are raw / absolute
(un-prefixed, like
sadd/publish). Returns whatever the script returns. Used byWSRouterfor the race-free per-room server-set. - exists() : bool
- Returns
truewhen the row for$keyexists in the named table. - get() : mixed
- Fetch a row or a single field from the named table.
- incr() : int|float
- Atomically increment a numeric column in a row.
- iterate() : Generator<string, array<string, scalar>>
- Yield every row in the named table as
$key => $row. -
iteratePaged()
: array{cursor: string, rows: array
>} - Cursor-based paginated iteration of the named table.
- make() : void
- Register a table schema on the Redis backend.
- mget() : array<string, array<string, scalar>|null>
- Fetch multiple rows in a single pipelined round-trip.
- mset() : bool
- Write multiple rows in a single pipelined round-trip.
- names() : array<int, string>
- Return the names of all tables registered on this backend via
make(). - ping() : bool
- Health check via
PING—Store::ping()delegates here. - pool() : RedisConnectionPool
- Returns the underlying
RedisConnectionPoolinstance. - prefix() : string
- Returns the key namespace prefix (e.g.
'zealstore'). - publish() : int
- Pub/sub publish through the pool. Returns the number of subscribers Redis delivered the message to.
- publishReliable() : string
- Append a message to a Redis Stream via
XADD. Auto-trims to$maxLenentries when set. The payload is stored under the'payload'field, matching the consumer-side convention inRedisStreams. - sadd() : int
- Add one or more members to a Redis SET at the given absolute
$key. - scard() : int
- Return the cardinality (number of members) of a Redis SET at the given
absolute
$key. O(1). Returns0when the key does not exist. - sdel() : bool
- Delete an absolute Redis SET key via
UNLINK(non-blocking reclaim). - set() : bool
- Write a row to the named table. Creates or overwrites the Redis HASH at
{prefix}:{name}:{key}and, in'tracked'mode, adds$keyto the membership SET. AppliesEXPIREin'ttl'mode. - srem() : int
- Remove one or more members from a Redis SET at the given absolute
$key. -
sscanCursor()
: array{0: string, 1: list
} - Cursor-based
SSCANon an absolute SET key — one batch per call. - url() : string
- Returns the Redis connection URL this backend was constructed with.
- assertMade() : void
- Assert that
$namewas registered viamake(), throwingStoreExceptionotherwise. - countViaScan() : int
- Count rows in
'ttl'mode viaSCAN MATCH— O(N). - rowKey() : string
- Build the Redis HASH key for a specific row:
{prefix}:{table}:{key}. - setKey() : string
- Build the Redis SET key for the membership index:
{prefix}:{table}:__keys__.
Properties
$codec
Encodes/decodes PHP scalars to/from Redis hash field strings.
private
TypeCodec
$codec
$pool
private
RedisConnectionPool
$pool
$prefix
private
string
$prefix
= 'zealstore'
$schemas
Per-table column schemas: table name → column name → [TYPE, size?].
private
array<string, array<string, array{0: int, 1?: int}>>
$schemas
= []
$tableOpts
Per-table options: table name → ['mode' => 'tracked'|'ttl', 'ttl' => int].
private
array<string, array{mode: string, ttl: int}>
$tableOpts
= []
Methods
__construct()
public
__construct(RedisConnectionPool $pool[, string $prefix = 'zealstore' ]) : mixed
Parameters
- $pool : RedisConnectionPool
-
Coroutine-safe connection pool.
- $prefix : string = 'zealstore'
-
Key namespace prefix (default
'zealstore').
clear()
Delete every row in the named table.
public
clear(string $name) : void
Uses UNLINK (non-blocking key reclaim, Redis 4.0+) in batches of 100
to avoid blocking the Redis event loop on large tables. In 'tracked'
mode also deletes the membership SET key.
Parameters
- $name : string
count()
Return the number of rows in the named table.
public
count(string $name) : int
In 'tracked' mode: O(1) via SCARD on the membership SET.
In 'ttl' mode: O(N) via SCAN MATCH (see countViaScan()).
Parameters
- $name : string
Return values
intdecr()
Atomically decrement a numeric column — delegates to incr() with -$by.
public
decr(string $name, string $key, string $col[, int|float $by = 1 ]) : int|float
Parameters
- $name : string
- $key : string
- $col : string
- $by : int|float = 1
Return values
int|float —The new value after decrementing.
del()
Delete a row from the named table.
public
del(string $name, string $key) : bool
In 'tracked' mode also removes $key from the membership SET.
Returns true when the key existed and was deleted, false otherwise.
Parameters
- $name : string
- $key : string
Return values
booleval()
Run a Lua script server-side (atomic). KEYS are raw / absolute
(un-prefixed, like sadd/publish). Returns whatever the script
returns. Used by WSRouter for the race-free per-room server-set.
public
eval(string $script[, array<int, string> $keys = [] ][, array<int, string> $args = [] ]) : mixed
Parameters
- $script : string
- $keys : array<int, string> = []
- $args : array<int, string> = []
exists()
Returns true when the row for $key exists in the named table.
public
exists(string $name, string $key) : bool
Parameters
- $name : string
- $key : string
Return values
boolget()
Fetch a row or a single field from the named table.
public
get(string $name, string $key[, string|null $field = null ]) : mixed
When $field is null, returns the full decoded row as
array<string, mixed> or null when the key does not exist.
When $field is provided, returns only that field's decoded value
(or null on miss).
Parameters
- $name : string
- $key : string
- $field : string|null = null
incr()
Atomically increment a numeric column in a row.
public
incr(string $name, string $key, string $col[, int|float $by = 1 ]) : int|float
Uses HINCRBY for TYPE_INT columns and HINCRBYFLOAT for TYPE_FLOAT.
Creates the row if it does not exist. In 'tracked' mode, adds the key to
the membership SET on first creation. Applies EXPIRE in 'ttl' mode.
Parameters
- $name : string
- $key : string
- $col : string
- $by : int|float = 1
Return values
int|float —The new value after incrementing.
iterate()
Yield every row in the named table as $key => $row.
public
iterate(string $name) : Generator<string, array<string, scalar>>
In 'tracked' mode, iterates the membership SET via SSCAN then
fetches each row with HGETALL. In 'ttl' mode, uses SCAN MATCH
across the keyspace. Acquires a dedicated connection from the pool for
the duration of iteration — do not hold the generator open longer than
necessary.
Parameters
- $name : string
Return values
Generator<string, array<string, scalar>>iteratePaged()
Cursor-based paginated iteration of the named table.
public
iteratePaged(string $name[, string $cursor = '0' ][, int $count = 100 ]) : array{cursor: string, rows: array>}
Returns one Redis SCAN/SSCAN batch at a time. Each call costs 2
round-trips: one SCAN/SSCAN + one pipelined HGETALL batch via
mhgetall(). Pass the returned 'cursor' value as the next call's
$cursor; iteration is complete when the returned cursor is '0'.
$cursor = '0';
do {
['cursor' => $cursor, 'rows' => $rows] =
Store::iteratePaged('my_table', $cursor, 50);
foreach ($rows as $key => $row) { // ... }
} while ($cursor !== '0');
Parameters
- $name : string
- $cursor : string = '0'
- $count : int = 100
Return values
array{cursor: string, rows: arraymake()
Register a table schema on the Redis backend.
public
make(string $name, int $maxRows, array<string, array{0: int, 1?: int}> $columns[, array<string, mixed> $opts = [] ]) : void
Must be called before any set/get/del/incr/count/iterate
operations on the named table. Accepts the same $columns shape as
TableBackend::make() (column => [TYPE, size?]). $maxRows is
advisory only — Redis has no hard cap; use maxmemory +
maxmemory-policy server-side instead.
$opts accepts:
'mode'—'tracked'(default) or'ttl'. See class docblock.'ttl'— TTL in seconds; required and >= 1 whenmode = 'ttl'.
Parameters
- $name : string
- $maxRows : int
- $columns : array<string, array{0: int, 1?: int}>
-
Column definitions.
- $opts : array<string, mixed> = []
-
Table options.
Tags
mget()
Fetch multiple rows in a single pipelined round-trip.
public
mget(string $name, array<int, string> $keys) : array<string, array<string, scalar>|null>
Returns a map of key → decoded row for every key in $keys. Missing
keys map to null. Uses mhgetall() (pipelined HGETALL) internally —
O(1) round-trips regardless of batch size.
Parameters
- $name : string
- $keys : array<int, string>
Return values
array<string, array<string, scalar>|null>mset()
Write multiple rows in a single pipelined round-trip.
public
mset(string $name, array<string, array<string, bool|float|int|string>> $rows) : bool
Uses mhsetWithMembership() internally — one pipeline for all HMSET +
optional EXPIRE + a single SADD for tracked-mode membership.
Idempotent on existing keys (tracked SET ignores duplicate members).
Returns true on success.
Parameters
- $name : string
- $rows : array<string, array<string, bool|float|int|string>>
-
Key → column-value map.
Return values
boolnames()
Return the names of all tables registered on this backend via make().
public
names() : array<int, string>
Return values
array<int, string>ping()
Health check via PING — Store::ping() delegates here.
public
ping() : bool
Return values
boolpool()
Returns the underlying RedisConnectionPool instance.
public
pool() : RedisConnectionPool
Return values
RedisConnectionPoolprefix()
Returns the key namespace prefix (e.g. 'zealstore').
public
prefix() : string
Return values
stringpublish()
Pub/sub publish through the pool. Returns the number of subscribers Redis delivered the message to.
public
publish(string $channel, string $payload) : int
Parameters
- $channel : string
- $payload : string
Return values
intpublishReliable()
Append a message to a Redis Stream via XADD. Auto-trims to $maxLen
entries when set. The payload is stored under the 'payload' field,
matching the consumer-side convention in RedisStreams.
public
publishReliable(string $stream, string $payload[, int|null $maxLen = null ]) : string
Parameters
- $stream : string
- $payload : string
- $maxLen : int|null = null
Return values
string —The Redis-generated message id (e.g. '1626300000000-0').
sadd()
Add one or more members to a Redis SET at the given absolute $key.
public
sadd(string $key, string ...$members) : int
The key is NOT prefixed — callers own the namespace (used by Room).
Returns the number of NEW members added (existing members are ignored).
Parameters
- $key : string
- $members : string
Return values
intscard()
Return the cardinality (number of members) of a Redis SET at the given
absolute $key. O(1). Returns 0 when the key does not exist.
public
scard(string $key) : int
Parameters
- $key : string
Return values
intsdel()
Delete an absolute Redis SET key via UNLINK (non-blocking reclaim).
public
sdel(string $key) : bool
Returns true when the key was present and unlinked.
Parameters
- $key : string
Return values
boolset()
Write a row to the named table. Creates or overwrites the Redis HASH at
{prefix}:{name}:{key} and, in 'tracked' mode, adds $key to the
membership SET. Applies EXPIRE in 'ttl' mode.
public
set(string $name, string $key, array<string, bool|float|int|string> $row) : bool
Parameters
- $name : string
- $key : string
- $row : array<string, bool|float|int|string>
-
Column values to store.
Return values
boolsrem()
Remove one or more members from a Redis SET at the given absolute $key.
public
srem(string $key, string ...$members) : int
Returns the number of members that were actually removed.
Parameters
- $key : string
- $members : string
Return values
intsscanCursor()
Cursor-based SSCAN on an absolute SET key — one batch per call.
public
sscanCursor(string $key, string $cursor, int $count) : array{0: string, 1: list}
Parameters
- $key : string
- $cursor : string
- $count : int
Return values
array{0: string, 1: list[nextCursor, members]
url()
Returns the Redis connection URL this backend was constructed with.
public
url() : string
Return values
stringassertMade()
Assert that $name was registered via make(), throwing StoreException otherwise.
private
assertMade(string $name) : void
Parameters
- $name : string
Tags
countViaScan()
Count rows in 'ttl' mode via SCAN MATCH — O(N).
private
countViaScan(string $name) : int
Only called from count() when the table mode is 'ttl'.
Parameters
- $name : string
Return values
introwKey()
Build the Redis HASH key for a specific row: {prefix}:{table}:{key}.
private
rowKey(string $table, string $key) : string
Parameters
- $table : string
- $key : string
Return values
stringsetKey()
Build the Redis SET key for the membership index: {prefix}:{table}:__keys__.
private
setKey(string $table) : string
Parameters
- $table : string