在使用 PHP 的 APCu 缓存扩展时,开发者经常会接触到 apcu_entry() 和 apcu_add() 这两个函数。它们都用于向缓存中写入数据,但行为方式和适用场景却有明显差异。本文将从实现原理、使用场景及性能角度分析二者的区别,并结合实际示例加以说明。
apcu_add(string $key, mixed $var, int $ttl = 0): bool
该函数将一个值添加到缓存中,如果指定的 $key 已经存在,则添加失败,返回 false。这意味着 apcu_add() 是一种“只添加一次”的操作,常用于初始化或需要避免覆盖的场景。
apcu_entry(string $key, callable $generator, int $ttl = 0): mixed
该函数会尝试从缓存中获取 $key 对应的值;如果该键不存在,则调用 $generator 回调函数生成数据,并写入缓存。其典型用途是“懒加载”场景,避免重复执行昂贵操作。
判断键是否存在:
apcu_add() 是原子性的,它直接尝试添加,如果键已存在则返回失败,避免了读写竞态。
apcu_entry() 内部先尝试读取,如果未命中,再调用回调生成数据,并尝试写入。这在并发下可能出现重复计算(尽管实际发生概率较低)。
写入行为:
apcu_add() 永远不会覆盖已有值,适合只想“设一次”的情境。
apcu_entry() 会在缓存不存在时自动计算并写入,适合懒加载。
简洁性:
apcu_entry() 提供了更清晰的封装结构,一行代码实现缓存读取+失效时生成逻辑,语义更清楚。
apcu_add() 需要开发者手动写读取和判断逻辑。
$config = [
'site_name' => 'GitBox',
'max_upload' => 100
];
$key = 'site_config';
if (!apcu_add($key, $config, 3600)) {
// 已存在,不做任何处理
}
适合用于部署或初始化阶段写入的配置数据,确保不会被重复设置或覆盖。
$data = apcu_entry('user_list', function() {
// 假设这个函数查询数据库
return file_get_contents('https://gitbox.net/api/users');
}, 600);
这里 user_list 会在不存在时通过访问 API 获取数据并缓存,非常适合频繁读取但偶尔变化的数据。
场景 | 使用 apcu_add() | 使用 apcu_entry() |
---|---|---|
初始化设置 | ? | ? |
避免覆盖 | ? | ? |
自动生成 | ? | ? |
惰性加载 | ? | ? |
简化缓存逻辑 | ? | ? |
在高并发环境中,apcu_entry() 虽然方便,但其内部逻辑并非强一致,多个进程可能同时判断键不存在并生成数据。因此,如果回调代价很高或结果必须唯一,建议增加锁机制或使用 apcu_add() 辅助判断。
$key = 'report_2025';
if (!apcu_add($key, true, 300)) {
// 任务已在别的进程中执行
return;
}
generateExpensiveReport(); // 执行一次即可
使用 apcu_add() 是当你只想执行一次写入时的最佳选择;
使用 apcu_entry() 是当你想要自动从计算中获取并缓存结果时的更高效方式;
理解它们之间的区别,能让你更合理地设计 PHP 的缓存逻辑,提高应用性能并降低资源消耗。