多语言缓存读不到主因是键名未嵌入语言标识、Redis未配prefix导致冲突、store隔离使file/redis缓存不互通;须手动拼locale到键名、配置统一prefix、确保store显式定义并避免fallback。

Cache::get() 返回 null 时,大概率不是代码写错了,而是缓存根本没写进去,或写进去了却读不到——多语言场景下尤其容易栽在键名、前缀、store 隔离这三处。
为什么多语言缓存总读不到?键名没带语言标识
ThinkPHP 默认不自动注入语言上下文到缓存键里。你用 Cache::set('menu', $data) 存菜单,中英文环境都写同一个键,必然互相覆盖或错读。
常见错误现象:切换语言后页面没变、部分文案回退成默认语言、后台改了翻译前端不生效。
- 必须手动把当前语言标识(如
app()->getLocale()或Lang::locale())拼进键名,例如:Cache::set('menu_' . app()->getLocale(), $data, 3600) - 避免用中文、空格、斜杠等非法字符作键名;推荐统一转小写+下划线,比如
'menu_zh_cn'、'menu_en_us' - 如果用了
Cache::tag()管理多语言缓存,记得 tag 名也要带 locale,否则Cache::tag('menu')->clear()会清掉所有语言版本
Redis 多语言缓存必须配 prefix,否则键名冲突
多个语言包共用一个 Redis 实例时,若没设 prefix,menu_zh_cn 和 menu_en_us 会被当成普通字符串写入,但清理、监控、调试时极易混淆,甚至被其他项目误删。
性能影响:无直接性能损耗,但运维成本陡增;线上出问题时无法快速定位是哪个语言的缓存异常。
立即学习“PHP免费学习笔记(深入)”;
- 在
config/cache.php的stores['redis']配置里,明确设置'prefix' => 'lang_'(不要为空) - 注意:这个
prefix是加在你传入的键名前面的,最终 Redis 里存的是lang_menu_zh_cn,不是lang_lang_menu_zh_cn - 如果项目已上线且缓存键没带 locale,又不能停服重建,可用
KEYS lang_menu_*+RENAME批量补前缀,但需确认 Redis 没启用cluster模式(否则 KEYS 不可用)
Cache::store('redis') 和 Cache::store('file') 切换时数据不互通
多语言环境下常想“开发用 file,上线切 redis”,结果发现本地测好的多语言缓存一上生产就 null——因为两个 store 完全隔离,键名一样也不共享数据。
典型误用:在 config 中把 'default' => 'file',却在代码里显式调用 Cache::store('redis')->get('menu_zh_cn'),而配置里压根没定义 stores['redis'],这时 TP6 会静默 fallback 到 file,但 file 驱动下带下划线的键名可能生成非法文件路径,直接写失败。
- 确保
config/cache.php中stores数组里真有对应名字的配置,比如写了Cache::store('redis'),就必须有'redis' => [ 'type' => 'redis', ... ] - 检查 PHP 是否已加载
redis扩展:php -m | grep redis;没装会报Class 'Redis' not found,但缓存操作仍继续执行(只是不存不取) - 多语言 + 多 store 场景下,别依赖“自动 fallback”,所有
Cache::store(...)调用都应有明确配置支撑
缓存失效后没触发重载,多语言页面卡在旧文案
缓存过期只是数据不可读,不代表业务逻辑会自动重新生成并写入新缓存。很多多语言模块只在首次访问时生成缓存,后续靠定时任务或手动刷新,导致语言切换后文案长期不更新。
最容易被忽略的一点:Cache::get() 返回 null 后,你得自己判断并调用生成逻辑 + Cache::set(),框架不会帮你做这件事。
- 标准写法应是:
$data = Cache::get($key); if ($data === null) { $data = $this->generateLangData($locale); Cache::set($key, $data, 3600); } - 别在控制器里用
S('key', $val)(TP5 旧函数),TP6+ 已废弃,混用会导致Cache::get()读不到 - 如果语言包本身是 JSON 文件,建议加个文件 mtime 校验:读缓存前先比对
filemtime(lang_path() . "$locale.json")和缓存时间戳,不一致就强制刷新



















