Laravel中如何按前缀批量清除File驱动的缓存项?
问题
我希望移除所有键以自定义字符串开头的缓存项。目前我为Permission模型创建了PermissionObserver,通过自定义Trait ObserverEvent来调用handle方法,代码如下:
class PermissionObserver { use ObserverEvent; private function handle(Permission $permission) { $emails = User::pluck('email'); foreach ($emails as $email) { $key = 'permission_index_'. $email; if (cache()->has($key)) { cache()->forget($key); } } $ids = User::pluck('id'); foreach ($ids as $id) { $key1 = 'permission_create_users_'. $id; $key2 = 'permission_edit__users_'. $id; if (cache()->has($key1)) { cache()->forget($key1); } if (cache()->has($key2)) { cache()->forget($key2); } } // It will continue like this.... logger()->build(CUSTOM_BUILD_LOG_CHANNEL)->info("PERMISSION_CACHE_CLEARED"); } }
现在这段代码越来越冗长,还出现了性能问题,且其他模型也存在类似逻辑。
补充说明:我未使用redis、database、dynamodb、memcached或octane缓存驱动,使用的是默认的file存储驱动,请问是否有办法清除所有键以permission开头的缓存,实现类似cache()->forget('permission*')(该写法无效)的效果?
解决方案
由于Laravel的file缓存驱动不支持通配符删除,我们可以通过遍历缓存文件、匹配缓存键前缀的方式实现批量删除:
1. 封装通用批量删除方法
在项目中创建一个全局辅助函数或缓存工具类,实现按前缀删除缓存的逻辑:
use Illuminate\Support\Facades\Cache; use Illuminate\Cache\FileStore; function deleteCacheByPrefix(string $prefix): void { $store = Cache::store(); // 仅针对file驱动执行逻辑 if (!$store instanceof FileStore) { return; } $cacheDirectory = $store->getDirectory(); $files = scandir($cacheDirectory); foreach ($files as $file) { $filePath = $cacheDirectory . DIRECTORY_SEPARATOR . $file; // 跳过目录和非PHP缓存文件 if (is_dir($filePath) || !str_ends_with($file, '.php')) { continue; } $content = file_get_contents($filePath); // 匹配Laravel file缓存中的键字段格式 if (preg_match('/"key";s:\d+:"(.*?)"/', $content, $matches)) { $cacheKey = $matches[1]; if (str_starts_with($cacheKey, $prefix)) { // 调用Laravel的forget方法删除,会自动处理缓存过期等逻辑 Cache::forget($cacheKey); // 也可以直接删除文件:unlink($filePath); } } } }
2. 简化Observer代码
修改PermissionObserver的handle方法,直接调用封装好的方法即可:
private function handle(Permission $permission) { deleteCacheByPrefix('permission_'); logger()->build(CUSTOM_BUILD_LOG_CHANNEL)->info("PERMISSION_CACHE_CLEARED"); }
3. 注意事项
- 若缓存文件数量极大,遍历操作可能会有短暂性能消耗,建议在低峰期执行,或定期清理缓存目录。
- 该方法可复用至其他模型的Observer,只需传入对应缓存键前缀即可,避免重复编写冗长的遍历逻辑。
内容的提问来源于stack exchange,提问作者Moxley
相关产品推荐
相关产品推荐

