PHP与Redis缓存实践完整方案 PHP与Redis缓存实践完整方案Redis在PHP项目里太常用了。缓存、队列、计数器、排行榜各种场景都能用上。今天写一份完整的Redis实践指南。先从最基础的连接和基本操作说起。php// 连接Redis$redis new Redis();$redis-connect(127.0.0.1, 6379);// 如果有密码// $redis-auth(password);// 选择数据库// $redis-select(1);echo 连接状态: . ($redis-ping() ? 正常 : 异常) . \n;// 字符串操作$redis-set(key1, value1);echo $redis-get(key1) . \n;// 带过期时间的设置$redis-setex(session:123, 3600, user_data);$redis-set(temp, 临时数据, 60); // 60秒过期// 批量操作$redis-mSet([k1 v1, k2 v2, k3 v3]);$values $redis-mGet([k1, k2, k3]);print_r($values);?List可以用作队列或栈。php// 列表操作$redis-del(queue);// 从左边推入$redis-lPush(queue, 任务C);$redis-lPush(queue, 任务B);$redis-lPush(queue, 任务A);// 从右边弹出先进先出while ($task $redis-rPop(queue)) {echo 处理: $task\n;}// 队列长度$redis-lPush(queue, task1, task2, task3);echo 队列长度: . $redis-lLen(queue) . \n;// 范围获取$range $redis-lRange(queue, 0, -1);print_r($range);// 阻塞弹出等待队列有数据// $task $redis-brPop([queue], 5); // 等待5秒?Hash适合存储对象类型的数据。php$redis-del(user:1001);// 存储用户信息$redis-hSet(user:1001, name, 张三);$redis-hSet(user:1001, age, 28);$redis-hSet(user:1001, email, zhangsantest.com);// 获取单个字段echo 姓名: . $redis-hGet(user:1001, name) . \n;// 获取所有字段$user $redis-hGetAll(user:1001);print_r($user);// 批量设置$redis-hMSet(user:1002, [name 李四,age 35,email lisitest.com,]);// 字段是否存在echo 存在name: . ($redis-hExists(user:1002, name) ? 是 : 否) . \n;// 获取所有键和值$fields $redis-hKeys(user:1001);$values $redis-hVals(user:1001);print_r($fields);print_r($values);// 计数器$redis-hIncrBy(user:1001, login_count, 1);echo 登录次数: . $redis-hGet(user:1001, login_count) . \n;?Set适合做集合运算。php// 用户标签$redis-sAdd(user:1:tags, PHP, JavaScript, MySQL, Redis);$redis-sAdd(user:2:tags, PHP, Python, Docker, Redis);// 共同标签交集$commonTags $redis-sInter(user:1:tags, user:2:tags);echo 共同标签: . implode(, , $commonTags) . \n;// 所有标签并集$allTags $redis-sUnion(user:1:tags, user:2:tags);echo 所有标签: . implode(, , $allTags) . \n;// 差异标签$diffTags $redis-sDiff(user:1:tags, user:2:tags);echo User1特有: . implode(, , $diffTags) . \n;// 随机获取成员$random $redis-sRandMember(user:1:tags, 2);echo 随机标签: . implode(, , $random) . \n;// 集合大小echo User1标签数: . $redis-sCard(user:1:tags) . \n;?Sorted Set有序集合适合排行榜场景。php// 游戏排行榜$redis-zAdd(leaderboard, 9500, 张三);$redis-zAdd(leaderboard, 8800, 李四);$redis-zAdd(leaderboard, 9200, 王五);$redis-zAdd(leaderboard, 7800, 赵六);$redis-zAdd(leaderboard, 9900, 钱七);// 获取前3名从高到低$top3 $redis-zRevRange(leaderboard, 0, 2, true);echo 排行榜前三:\n;foreach ($top3 as $player $score) {echo $player: $score分\n;}// 获取某人的排名$rank $redis-zRevRank(leaderboard, 李四);echo 李四排名: 第 . ($rank 1) . 名\n;// 获取某人的分数echo 张三分数: . $redis-zScore(leaderboard, 张三) . \n;// 增加分数$redis-zIncrBy(leaderboard, 100, 王五);echo 王五加分后: . $redis-zScore(leaderboard, 王五) . \n;// 统计分数区间人数$count $redis-zCount(leaderboard, 8000, 9500);echo 8000-9500分人数: $count\n;?Redis的发布订阅模式可以用于消息通知。php// 发布者function publishMessage(Redis $redis, string $channel, string $message): void{$redis-publish($channel, $message);echo 已发布到频道 $channel: $message\n;}$redis new Redis();$redis-connect(127.0.0.1, 6379);publishMessage($redis, notifications, 有新订单);publishMessage($redis, notifications, 用户注册成功);?Redis的Lua脚本可以在服务端执行原子操作。php$redis new Redis();$redis-connect(127.0.0.1, 6379);// Lua脚本限流$rateLimitScript local key KEYS[1]local limit tonumber(ARGV[1])local window tonumber(ARGV[2])local current redis.call(GET, key)if current and tonumber(current) limit thenreturn 0endredis.call(INCR, key)redis.call(EXPIRE, key, window)return 1;$redis-eval($rateLimitScript, [rate_limit:api, 100, 60], 1);echo 请求通过\n;?分布式锁也是Redis的常见用途。class RedisLock{private Redis $redis;private string $prefix lock:;private int $defaultTTL 10;public function __construct(Redis $redis){$this-redis $redis;}public function acquire(string $key, int $ttl null): ?string{$ttl $ttl ?: $this-defaultTTL;$lockKey $this-prefix . $key;$token bin2hex(random_bytes(16));// SET NX EX 原子操作$result $this-redis-set($lockKey, $token, [NX, EX $ttl]);if ($result) {return $token;}return null;}public function release(string $key, string $token): bool{$lockKey $this-prefix . $key;// Lua脚本保证原子性只有持有锁的人才能释放$script if redis.call(GET, KEYS[1]) ARGV[1] thenreturn redis.call(DEL, KEYS[1])elsereturn 0end;return (bool)$this-redis-eval($script, [$lockKey, $token], 1);}public function withLock(string $key, callable $callback, int $ttl null): mixed{$token $this-acquire($key, $ttl);if ($token null) {throw new RuntimeException(无法获取锁: $key);}try {return $callback();} finally {$this-release($key, $token);}}}$redis new Redis();$redis-connect(127.0.0.1, 6379);$lock new RedisLock($redis);try {$lock-withLock(process:order:123, function () {echo 处理订单中...\n;sleep(1);echo 订单处理完成\n;return [status success];});} catch (RuntimeException $e) {echo 错误: {$e-getMessage()}\n;}?Redis在实际项目中的性能优势很明显。但要注意内存管理设置合理的过期策略。还有持久化配置RDB和AOF各有优劣。数据结构的选用也要看具体场景不是所有数据都适合放Redis。