本文目录导读:

在PHP项目中实现文件缓存过期自动清理,常见有以下几种方案:
惰性检查法(推荐)
每次读取缓存时检查过期时间,过期则删除。
class FileCache
{
private $cacheDir;
public function __construct($cacheDir = '/tmp/cache')
{
$this->cacheDir = $cacheDir;
}
public function get($key)
{
$file = $this->getFilePath($key);
if (!file_exists($file)) {
return null;
}
// 读取缓存数据和过期时间
$data = file_get_contents($file);
$cache = unserialize($data);
// 检查是否过期
if (time() > $cache['expire_time']) {
unlink($file); // 删除过期缓存
return null;
}
return $cache['data'];
}
public function set($key, $data, $ttl = 3600)
{
$file = $this->getFilePath($key);
$cache = [
'expire_time' => time() + $ttl,
'data' => $data
];
file_put_contents($file, serialize($cache));
}
private function getFilePath($key)
{
$hash = md5($key);
return $this->cacheDir . '/' . $hash . '.cache';
}
}
定时清理脚本(Cron Job)
创建专门的清理脚本,定期清理过期缓存。
清理脚本 cleanup_cache.php:
<?php
// 缓存目录
$cacheDir = '/tmp/cache';
// 递归清理过期文件
function cleanExpiredCache($dir, $maxLifetime = 3600) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$fullPath = $dir . '/' . $file;
if (is_dir($fullPath)) {
cleanExpiredCache($fullPath, $maxLifetime);
} elseif (is_file($fullPath)) {
$fileModTime = filemtime($fullPath);
if (time() - $fileModTime > $maxLifetime) {
unlink($fullPath);
echo "Deleted: $fullPath\n";
}
}
}
}
// 执行清理
cleanExpiredCache($cacheDir);
?>
添加Cron任务:
# 每1小时清理一次过期文件 0 * * * * /usr/bin/php /path/to/cleanup_cache.php # 或者每天凌晨2点清理 0 2 * * * /usr/bin/php /path/to/cleanup_cache.php
懒清理 + 概率清理
请求到达时随机检查清理部分缓存文件。
class ProbabilisticCache
{
private $cacheDir;
private $probability = 0.01; // 1% 概率
public function get($key)
{
// 随机触发清理
if (mt_rand(1, 100) / 100 <= $this->probability) {
$this->partialClean();
}
// 正常获取缓存逻辑...
}
private function partialClean()
{
$files = glob($this->cacheDir . '/*.cache');
$count = min(10, count($files)); // 每次最多清理10个
if ($count === 0) return;
$keys = array_rand($files, $count);
if (!is_array($keys)) {
$keys = [$keys];
}
foreach ($keys as $index) {
$file = $files[$index];
$data = unserialize(file_get_contents($file));
if (time() > $data['expire_time']) {
unlink($file);
}
}
}
}
基于文件系统的优雅方案
class SmartCache
{
private $cacheDir;
public function get($key, $ttl = 3600)
{
$file = $this->getFilePath($key);
if (!file_exists($file)) {
return null;
}
// 使用文件mtime判断过期
if (time() - filemtime($file) > $ttl) {
unlink($file);
return null;
}
return unserialize(file_get_contents($file));
}
public function set($key, $data)
{
$file = $this->getFilePath($key);
file_put_contents($file, serialize($data));
// touch 设置文件修改时间
touch($file);
}
public function cleanAll()
{
$files = glob($this->cacheDir . '/*');
foreach ($files as $file) {
if (is_file($file)) {
unlink($file);
}
}
}
}
使用类似PHPAPC的解决方案
// 如果安装了APCu扩展
class ApcuCache
{
public function get($key)
{
return apcu_fetch($key);
}
public function set($key, $data, $ttl = 3600)
{
apcu_store($key, $data, $ttl);
}
// APCu自动处理过期清理,无需手动操作
}
最佳实践建议
-
生产环境推荐使用方案1(惰性检查),简单高效。
-
结合使用Cron任务,定期清理完全过期的文件。
-
合理设置缓存TTL,避免过多的碎片文件。
-
使用目录分层,避免单个目录文件过多:
// 对缓存key进行目录分层
private function getFilePath($key)
{
$hash = md5($key);
$dir1 = substr($hash, 0, 2);
$dir2 = substr($hash, 2, 2);
$cacheDir = $this->cacheDir . '/' . $dir1 . '/' . $dir2;
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0777, true);
}
return $cacheDir . '/' . $hash . '.cache';
}
方案可以根据项目规模和需求选择使用,对于小型项目,惰性检查法就足够了;大型项目可以结合Cron任务和惰性检查。