only array cache can be push
问答 ThinkPHP
chen · 1月前
分享 收藏 评论
AI智能回答
0 个评论
提示: 安装或使用过程中遇到的 常见问题 ,点击查看更快解决您的问题!
登录后评论
网站报错only array cache can be push,定位到是common.php 缓存数据格式污染导致的, ![](https://static.easyadmin8.top/EasyAdmin8/QA/2026-05-13___30303030-3030-4030-b739-30754b6e6770_1778664693.png) ![](https://static.easyadmin8.top/EasyAdmin8/QA/2026-05-13___30303030-3030-4030-b739-30666a554e71_1778664768.png)
这是一个典型的 **缓存数据类型不匹配** 导致的运行时错误。错误提示 `only array cache can be push` 明确表示:程序在执行缓存写入/追加操作时,期望接收的是数组类型,但实际读取到的缓存值已被污染成其他类型(如字符串、整型、null、序列化对象或 Redis 的非 List 类型)。 由于我无法直接查看你提供的截图,以下提供一套标准且可落地的排查与修复方案,适用于大多数 PHP 后端(包括 EasyAdmin8 常见底层框架)。 --- ### 🔍 一、问题根因分析 | 可能原因 | 说明 | |:---|:---| | **历史异常残留** | 某次请求失败未处理返回值,导致非数组数据覆盖了原本应为数组的缓存键 | | **手动改库/删表/清空插件** | 直接修改了数据库或缓存文件,破坏原有结构 | | **反序列化/JSON 解析未判空** | `json_decode()` 或 `unserialize()` 失败返回 `null`,后续未做类型回退 | | **多端并发写入冲突** | 多个进程同时读写同一缓存键,中间状态被错误持久化 | | **Redis 类型混用** | 同一 Key 曾被当 String 存过,后被当 List/Hash 使用,客户端校验拦截 | --- ### 🛠️ 二、快速恢复方案(优先执行) 1. **定位具体缓存 Key** 在 `common.php` 报错行上方临时加入: ```php \Log::debug('Cache debug', [ 'key' => $your_cache_key, 'type' => gettype($current_cache_value), 'raw' => var_export($current_cache_value, true), 'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3) ]); ``` 2. **清理脏缓存** - **Redis**:`redis-cli DEL <缓存key>` 或使用框架命令 `php think cache:clear` / `php artisan cache:clear` - **File**:删除 `runtime/cache/` 或对应目录下的过期/损坏文件 - **后台**:通过 EasyAdmin 系统设置 → 缓存管理 → 一键清理 3. **重启服务**(如有 OPcache/Swoole/FPM) --- ### 💻 三、代码层根治建议(修改 `common.php`) #### ✅ 1. 安全读取 + 类型兜底 ```php // 原代码可能类似:$data = cache()->get('xxx'); $data = cache_get('xxx_key'); // 增加类型保护,污染时自动重置为数组 if (!is_array($data)) { \Log::warning("Cache format corrupted for key xxx_key, resetting to []."); $data = []; // 可选:从源头重新初始化默认数据 $data = load_default_array_data(); } ``` #### ✅ 2. 安全 Push/追加逻辑 ```php // 确保始终是数组再追加 $cacheValue = is_array($cacheValue) ? $cacheValue : []; $newItem = ['id' => 1, 'status' => 1]; $cacheValue[] = $newItem; // 重新写入(注意 TTL 保持一致) cache_set('xxx_key', $cacheValue, 3600); ``` #### ✅ 3. 避免直接覆盖已存在的 Key 如果你是在做 `list` 或 `stack` 类型的缓存,务必确认目标 Key 之前没有被写入过非数组值: ```php // ❌ 危险写法 cache_put('user_list', json_encode(['name'=>'test'])); // ✅ 正确做法 $current = cache_get('user_list') ?: []; if (!is_array($current)) $current = []; $current[] = ['name'=>'test']; cache_put('user_list', $current); ``` --- ### 🧭 四、排查 Checklist - [ ] 打开 `common.php`,找到触发 `push`/写入的精确行号 - [ ] 检查该行之前是否有 `return ''`、`die()`、或数据库查询未判空直接赋值 - [ ] 确认该缓存 Key 是否被其他插件/脚本单独使用(键名冲突) - [ ] 查看 Web 服务器/应用日志,寻找第一次出现脏数据的请求时间点 - [ ] 如果是 Redis,执行 `TYPE your_cache_key` 确认当前底层数据结构 --- ### 📦 五、预防最佳实践 1. **统一缓存入口封装**:不要频繁调用原生 `cache()`/`Cache::`,建议在公共类中提供 `SafeCache::get/set/push` 2. **强类型约定**:团队规范规定数组类缓存必须以 `_arr` 后缀结尾,便于肉眼审查 3. **加数据指纹校验**(可选): ```php $payload = [ 'data' => $arrayValue, '_v' => md5(json_encode($arrayValue)) ]; cache_set($key, $payload); ``` 4. **监控告警**:对核心缓存键设置定时校验任务,发现类型偏差自动预警或自愈 --- 如果你能提供 `common.php` 中报错行前后的 **3~5 行代码**(注意脱敏敏感信息),我可以给出更精确的重构片段。通常只需加上 `is_array()` 判断+容错重置,即可彻底杜绝此类问题复发。