学会这篇,你就能搞清 PHP 里文件缓存、Redis、Memcached 三种方案各自适合什么场景,并能在自己的项目里选出合适的一种落地。
PHP 缓存的本质很简单:把「算一次很贵、但短时间内不会变」的结果存起来,下次直接读。难点不在存,而在选哪种存法。下面按「先动手跑起来,再对比选型」的顺序讲。
第一步:先想清楚缓存什么、键怎么设计
缓存对象通常三类:SQL 查询结果、远程 API 响应、渲染好的 HTML 片段。
键名建议用「模块:对象:参数」的格式,例如 `post:detail:1024`,再统一加个前缀 `mysite:`,方便按前缀批量清理。键名不要塞中文和超长字符串,用 `md5()` 压缩一层更稳。
注意:键名设计错了,后期清理缓存只能整库 flush,会误伤其他业务。
第二步:文件缓存——零依赖,先跑起来
适合单机、访问量不大、缓存内容体积小的场景。核心就是写文件 + 存过期时间:
function cache_get(string $key, int $ttl = 3600) {
$file = __DIR__ . '/cache/' . md5($key) . '.php';
if (!is_file($file)) return null;
$data = include $file;
if ($data['expire'] < time()) { @unlink($file); return null; }
return $data['value'];
}
function cache_set(string $key, $value, int $ttl = 3600): void {
$file = __DIR__ . '/cache/' . md5($key) . '.php';
$data = ['expire' => time() + $ttl, 'value' => $value];
file_put_contents($file, '<?php return ' . var_export($data, true) . ';', LOCK_EX);
}
几个实操要点:
- 缓存目录必须可写(`chmod 755`,属主与 PHP 运行用户一致);
- 文件名用 `md5()` 后按前两位建子目录,避免单目录几万个文件拖慢 IO;
- 配套开 OPcache,`.php` 缓存文件会被编译缓存命中,比读纯文本再 `unserialize` 更快。
注意:文件缓存天生不支持多机共享。一旦上了负载均衡,两台机器缓存不一致,脏数据问题会非常难查。
第三步:Redis——功能最全,能当缓存也能当队列
安装(以 Ubuntu 为例):
sudo apt install redis-server php-redis
sudo systemctl enable --now redis-server
redis-cli ping # 返回 PONG 即成功
宝塔面板用户直接在「软件商店」装 Redis,再到「PHP 扩展」里勾选 redis 即可。装完 `php -m | grep redis` 确认扩展加载。
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 1.0);
$redis->setex('post:detail:1024', 3600, json_encode($post));
$post = json_decode($redis->get('post:detail:1024'), true);
$redis->incr('post:views:1024'); // 计数类场景,Redis 是首选
Redis 的优势在于数据结构丰富:String、Hash、List、Set、ZSet 全都有,点赞集合、排行榜、延迟队列都能直接做;还支持 RDB/AOF 持久化,重启不丢数据。
注意:别把 Redis 当数据库用。缓存一定要设 TTL,否则内存被慢慢吃满,触发 `maxmemory` 淘汰策略时会开始删你的数据。
第四步:Memcached——最纯粹的 KV,胜在简单
sudo apt install memcached php-memcached
sudo systemctl enable --now memcached
$mc = new Memcached();
$mc->addServer('127.0.0.1', 11211);
$mc->set('post:detail:1024', $post, 3600);
$post = $mc->get('post:detail:1024');
Memcached 只做一件事:内存 KV 缓存,多线程模型,纯读写场景下延迟极低。但它没有持久化(重启即清空)、没有复杂数据结构、单条 value 默认上限 1MB。
注意:Memcached 的 key 最长 250 字节,超长 key 直接写入失败且不报错,务必先 `md5()`。
第五步:三者横向对比与选型
| 维度 | 文件缓存 | Redis | Memcached |
|---|
| 依赖 | 无 | 需装服务 + 扩展 | 需装服务 + 扩展 |
| 多机共享 | 不支持 | 支持 | 支持 |
| 数据结构 | 无(自行序列化) | 丰富 | 仅 KV |
| 持久化 | 天然持久 | 支持 | 不支持 |
| 典型场景 | 单机小站、配置缓存 | 会话、计数、队列、榜单 | 纯页面/查询结果缓存 |
选型口诀:**单机小流量选文件,要共享或要复杂结构选 Redis,只想要最简单最快的 KV 选 Memcached**。新项目若无历史包袱,直接上 Redis,省得以后迁移。
第六步:写一层统一封装,别把驱动写死
在业务代码里直接 `new Redis()` 是灾难的开始。建议定义 `Cache::get()/set()/delete()` 三个方法,底层驱动可切换。
如果你维护的是 Clara BBS 这类无框架系统,插件里已经内置了 `Cache::remember(键, TTL, 回调)` 这类公共设施,直接调用即可,不必自己造轮子;后台「系统工具 → 缓存清理」用于清数据缓存,而插件是运行时钩子加载、保存即生效的,不存在编译缓存要清的问题。
注意:无论用哪种,都要防缓存穿透(查不到也缓存空值一小会儿)和雪崩(TTL 加随机抖动,别整点集体过期)。
小结
- 文件缓存零依赖,适合单机;记得分目录 + 开 OPcache。
- Redis 功能最全、支持持久化,是多机部署的默认答案;装完用 `redis-cli ping` 验证。
- Memcached 简单快,但无持久化、无复杂结构、value 有 1MB 上限。
- 缓存 key 统一前缀 + `md5()`,TTL 必设且加随机抖动。
- 业务层包一层 `Cache` 封装,换驱动不改业务代码。