fuyelk / redis
Redis的常用操作的封装
README
PHP 原生 Redis 扩展(ext-redis / phpredis)的轻量封装。
不是新客户端,也不替代 \Redis。调用方式与原生接近,在其上补齐业务里反复要写的那一层:前缀隔离、序列化、断线重连、原子锁、按集合批量删除。
未封装的命令仍可通过 __call 转到 phpredis(只给第一个标量参数加前缀)。
composer require fuyelk/redis
需要 PHP >= 7.4、ext-redis。2.0 为破坏性升级,从 1.x 迁移见 CHANGELOG.md。
解决什么问题
| 场景 | 原生 phpredis | 本库 |
|---|---|---|
| 一台 Redis 多个项目 | 键名自己约定,容易撞 | 自动加 prefix,项目之间数据隔离 |
set 数组 / 布尔 |
不能直接存,要自己 serialize | 写入自动编码,读取自动还原(不还原为对象) |
| Redis 闪断 | 抛异常,业务自己重连 | 最多重试 3 次(带退避),失败再抛,不把 PHP 卡死 |
| 防重复提交 / 回调解锁 | 自己拼 SETNX + EXPIRE,容易死锁或误删 |
lock / unlock:SET NX EX + token,可跨请求传凭证 |
| 按一批逻辑名清缓存 | 循环 DEL,还要记得加前缀 |
sAdd + delBySet |
| 列出 / 清空「当前项目」的键 | KEYS * 扫全库,生产会堵 |
keys / delAll / allData 只用 SCAN,且只动当前前缀 |
本库不写配置文件,不会在 vendor/ 下落盘。请自行单例,避免每个请求 new 一次。生产环境(多机、队列 Worker)必须显式传 prefix。
快速开始
$redis = new \fuyelk\redis\Redis([ 'host' => '127.0.0.1', 'password' => '', 'prefix' => 'myapp:', // 生产必须显式传入 ]); $redis->set('name', 'zhangsan'); $redis->get('name', 'default'); // key 不存在时返回默认值 $redis->set('profile', ['age' => 18]); // 数组可直接存取 if ($token = $redis->lock('submit', 10)) { // ... 业务 ... $redis->unlock('submit'); }
配置
优先级:构造参数 > 环境变量 > 默认值。
| 项 | 环境变量 | 默认 |
|---|---|---|
| host | REDIS_HOST |
127.0.0.1 |
| port | REDIS_PORT |
6379 |
| password | REDIS_PASSWORD |
空 |
| db | REDIS_DB |
0 |
| timeout | REDIS_TIMEOUT |
3 秒 |
| prefix | REDIS_PREFIX |
md5(getcwd()) 前 8 位 + : |
| expire | (仅构造参数) | 0 不过期 |
| persistent | (仅构造参数) | false |
未传 prefix 且未设环境变量时,用当前工作目录生成稳定前缀(同一台机器上不同项目不撞键)。多机部署 cwd 可能不同,不要依赖这个默认值。
方法示例
$redis = new \fuyelk\redis\Redis(['prefix' => 'myapp:']); $redis->set('name', 'zhangsan'); $redis->get('name', 'default'); $redis->setnx('exist', 'yes'); $redis->del('age'); $redis->inc('money', 5); $redis->dec('money', 5); // 集合 member 必须是未加库前缀的逻辑名 $redis->sAdd('users', 'user:1', 'user:2'); $redis->delBySet('users'); $redis->keys(); // 当前前缀下的键名(SCAN) $redis->allData(); // 当前前缀下的 string 数据(hash/list/set 会跳过) $redis->delAll(); // 只删当前前缀,不会清空整个 Redis
hash / list / set / zset 等未单独封装的命令,用法与 phpredis 相同,例如 $redis->hSet('user', 'name', 'alice')。
锁
lock 使用 SET key token NX EX seconds。成功返回 token 字符串(可直接 if ($redis->lock())),失败返回 false。
unlock($name, $token = null) 用 Lua:值等于 token 才删除。
- 同一请求:
unlock($name)即可。 - 支付回调等另一进程:加锁时把 token 存进业务数据,回调里
unlock($name, $savedToken)。 - 无 token 或 token 不匹配:不解,返回
false。避免迟到回调拆掉别人后来抢到的锁。
锁在 EX 秒后由 Redis 自动释放。不提供无凭证的强制解锁;若坚持按名字强删,可 $redis->del('lock:'.$name),须自行承担误删风险。
delBySet
sAdd('cache_keys', 'page:home') 的 member 是逻辑名,库只会给集合名加 prefix。
delBySet('cache_keys') 会对每个 member 再加一次 prefix 后删除,因此 member 不能已是完整 Redis key。若 member 已带库前缀,会删错键。