Cache::get()返回null主因是缓存驱动未切换至Redis而静默回退file驱动;须确认config/cache.php中default为小写'redis'、stores.redis配置完整(含type、select、password)、prefix一致且非空。

TP6.0 里 Cache::get() 总是 null?不是代码问题,八成是缓存压根没走 Redis —— 它静默 fallback 到了 file 驱动。
config/cache.php 中 default 和 stores.redis 必须同时配对生效
TP6.0 不再像 TP5.1 那样允许“写了 store('redis') 就自动启用”,它严格按配置路由。哪怕你只漏了一项,Cache::store('redis') 也会降级为 File 驱动,且不报错。
-
default必须是小写字符串'redis'(写成'Redis'或'REDIS'都会失败) -
stores.redis.type也必须是'redis'(TP6 统一小写,TP5.1 可接受大写但混用易出错) -
stores.redis.select必须是整数,写成"0"(字符串)会静默忽略,连接后无法选库 -
password字段不能省略:空密码也要显式写'',否则底层连接可能被 Redis 拒绝
cache() 助手函数传 0 和 null 的行为完全不同
很多人以为 cache('key', $val, 0) 是“永不过期”,结果 key 写进去就消失 —— 因为 TP6 底层把 0 当作「立即清除」语义,等价于 cache('key', null)。
-
cache('k', 'v', 0)→ 写入后立刻触发删除,实际没存住 -
cache('k', 'v', null)→ Redis 中不设 TTL,靠内存淘汰或手动清理(生产慎用,建议用大值如31536000) -
cache('k', 'v')→ 使用stores.redis.expire配置的默认值(默认3600秒)
Cache::store('redis') 写的 key 和 redis-cli 看不到,是因为前缀不一致
默认前缀是 think:cache:,所以 Cache::store('redis')->set('user_123', $data) 实际写的是 think:cache:user_123。你在命令行用 redis-cli keys "*" 找不到,很正常。
立即学习“PHP免费学习笔记(深入)”;
- 调试时想对得上:在
stores.redis中加'prefix' => 'dev:',然后用redis-cli keys "dev:*" - 需要原子操作(如
incr、hGetAll)时,别自己new \Redis(),改用think\facade\Cache::store('redis')->handler()->getRedis()或think\redis\Redis::instance()获取底层实例 - 绝对不要在队列任务里用原生
\Redis写,Web 层用Cache::get()读 —— 前缀不同,必然读不到
标签清理(tag clear)在 Redis 驱动下默认不生效
$cache->tag('user')->set('1001', $data) 后调 $cache->tag('user')->clear() 没反应?这不是 bug,是 TP6.x Redis 驱动的默认行为:它只靠 key 前缀模拟标签,clear() 仅做前缀匹配扫描,不维护 tag 索引。
- 要真正支持标签级清理,必须在
stores.redis中启用'use_tag_index' => true - 启用后依赖 Redis ≥ 6.0(需 SCAN + DEL 批量操作),每次
set()多写一条ZADD tag:user timestamp key,写入开销增加约 15%~20% - TP5.1 的标签清理是基于文件扫描的,天然不支持原子性;TP6.x 这个开关才是分布式环境下的关键能力
最常被忽略的是 select 类型和 password 显式声明 —— 它们不出错,但会让整个 Redis 缓存形同虚设。配完别急着写业务,先跑两行 php -r "var_dump(cache('test', 'ok', 10));" 和 php -r "var_dump(cache('test'));" 确认通路是否真通。



















