PHP应用版本动态更新时,如何清理APCu缓存?
解决方案:APCu缓存与应用版本同步清理
针对你在Apache2上运行的Composer构建PHP应用,需要在版本动态变更时清理对应APCu缓存的需求,这里有几个实用的方案,从低侵入的预防式到主动触发式都有,你可以根据自己的场景选择:
1. 版本前缀策略(推荐,低侵入性)
核心思路是给每个模块/包的APCu缓存键加上版本标识前缀,这样版本更新后,旧版本的缓存键会自动被弃用,无需主动删除,同时也能精准控制缓存范围。
实现步骤:
- 从Composer获取当前应用/模块版本(或者维护一个自定义的版本文件,比如
version.php):// 获取根包版本 $composerData = json_decode(file_get_contents(__DIR__ . '/composer.json'), true); $appVersion = $composerData['version']; // 或者获取特定模块版本(比如vendor下的包) $packageVersion = json_decode(file_get_contents(__DIR__ . '/vendor/your-vendor/your-package/composer.json'), true)['version']; - 在设置/读取APCu缓存时,拼接版本前缀:
// 以模块名为前缀+版本号+具体缓存键 $cacheKey = sprintf('module_%s:v%s:user_list', 'user', $appVersion); // 设置缓存 apcu_store($cacheKey, $userData, 3600); // 读取缓存 $cachedData = apcu_fetch($cacheKey); - 版本更新后,新的缓存会使用新的版本前缀,旧版本的缓存可以通过定期清理任务(比如CRON)删除,或者等待其自然过期。如果需要立即清理旧键,可以用
apcu_cache_info遍历并删除匹配旧版本前缀的键:function clearOldVersionCache(string $oldVersion) { $cacheInfo = apcu_cache_info(); foreach ($cacheInfo['cache_list'] as $item) { if (str_contains($item['info'], ":v{$oldVersion}:")) { apcu_delete($item['info']); } } }
2. 版本变更触发主动清理
如果需要在版本更新(比如composer update执行完成)后立即清理对应缓存,可以通过Composer的脚本钩子或者手动执行清理脚本实现。
方法A:Composer脚本钩子
在composer.json中添加post-update-cmd脚本,版本更新后自动运行清理逻辑:
{ "scripts": { "post-update-cmd": [ "php ./scripts/clear-apcu-cache.php" ] } }
然后编写clear-apcu-cache.php脚本:
<?php // 注意:如果APCu在CLI下默认未启用,需要在php.ini中开启apcu.enable_cli=1 // 清理所有模块的缓存(或指定版本的缓存) $cacheInfo = apcu_cache_info(); foreach ($cacheInfo['cache_list'] as $item) { // 可以根据模块前缀过滤,比如只清理user模块的缓存 if (str_starts_with($item['info'], 'module_user:')) { apcu_delete($item['info']); } } echo "APCu cache for updated modules cleared successfully.\n"; ?>
方法B:运行时版本检测清理
在应用的入口文件(比如index.php)中,添加版本检测逻辑,当发现版本变更时自动清理对应缓存:
<?php // 从composer.lock获取当前版本(比composer.json更准确,因为lock文件记录实际安装版本) $lockData = json_decode(file_get_contents(__DIR__ . '/composer.lock'), true); $currentVersion = $lockData['packages'][0]['version']; // 读取上次缓存的版本 $lastVersion = apcu_fetch('app_last_version'); if ($currentVersion !== $lastVersion) { // 版本变更,清理所有模块缓存或指定模块 clearOldVersionCache($lastVersion); // 更新缓存的版本记录 apcu_store('app_last_version', $currentVersion); } ?>
3. 注意事项
- APCu CLI启用:如果需要在CLI下运行清理脚本,确保
php.ini中apcu.enable_cli = On,否则CLI环境无法访问APCu缓存。 - 权限问题:Apache运行的PHP进程和CLI进程的APCu缓存是独立的(如果用的是APCu的共享内存模式),如果清理脚本在CLI运行,可能无法清理Apache进程的缓存。这种情况下,建议通过Web请求触发清理(比如一个带权限验证的清理接口),或者确保共享内存配置一致。
- 缓存键规范:提前统一模块/包的缓存键命名规则(比如
module_<name>:v<version>:<key>),这样后续清理时更容易匹配过滤。
内容的提问来源于stack exchange,提问作者Mostafa Barmshory




