本文目录导读:

为PHP项目的第三方接口数据实现本地缓存,常见方案及最佳实践如下:
文件缓存(简单场景)
基础实现
<?php
class FileCache {
private $cacheDir;
public function __construct($cacheDir = '/tmp/api_cache/') {
$this->cacheDir = $cacheDir;
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
}
public function get($key) {
$file = $this->cacheDir . md5($key) . '.cache';
if (!file_exists($file)) {
return false;
}
$data = unserialize(file_get_contents($file));
if ($data['expire'] < time()) {
unlink($file);
return false;
}
return $data['value'];
}
public function set($key, $value, $ttl = 3600) {
$data = [
'expire' => time() + $ttl,
'value' => $value
];
file_put_contents(
$this->cacheDir . md5($key) . '.cache',
serialize($data)
);
}
}
使用示例
$cache = new FileCache('/var/www/cache/');
$apiKey = 'weather_data';
if (!$data = $cache->get($apiKey)) {
// 请求第三方接口
$data = file_get_contents('https://api.weather.com/v1/...');
$data = json_decode($data, true);
// 缓存10分钟
$cache->set($apiKey, $data, 600);
}
return $data;
Redis缓存(高性能推荐)
安装与配置
# 安装Redis扩展 pecl install redis # 或使用composer composer require predis/predis
封装缓存类
<?php
class RedisCache {
private $redis;
private $prefix = 'api_cache:';
public function __construct($config = []) {
$this->redis = new Redis();
$this->redis->connect(
$config['host'] ?? '127.0.0.1',
$config['port'] ?? 6379
);
// 设置密码
if (!empty($config['password'])) {
$this->redis->auth($config['password']);
}
}
public function get($key) {
$data = $this->redis->get($this->prefix . $key);
return $data ? unserialize($data) : false;
}
public function set($key, $value, $ttl = 3600) {
$cacheKey = $this->prefix . $key;
$this->redis->setex($cacheKey, $ttl, serialize($value));
}
public function delete($key) {
$this->redis->del($this->prefix . $key);
}
public function exists($key) {
return $this->redis->exists($this->prefix . $key);
}
}
缓存策略封装
<?php
class ApiCacheManager {
private $cache;
private $defaultTTL = 300; // 默认5分钟
public function __construct($cache) {
$this->cache = $cache;
}
/**
* 获取或缓存API数据
*/
public function remember($key, $callback, $ttl = null) {
$cacheKey = md5($key);
// 1. 检查缓存
if ($data = $this->cache->get($cacheKey)) {
return $data;
}
// 2. 调用第三方API
try {
$data = call_user_func($callback);
// 3. 缓存数据
$this->cache->set(
$cacheKey,
$data,
$ttl ?? $this->defaultTTL
);
return $data;
} catch (Exception $e) {
// 异常处理:降级策略
return $this->handleFailure($cacheKey, $e);
}
}
/**
* 故障降级处理
*/
private function handleFailure($key, $e) {
// 1. 尝试返回过期缓存
if ($oldData = $this->cache->get($key . ':stale')) {
return $oldData;
}
// 2. 返回默认数据
$default = $this->getDefaultResponse();
// 3. 记录错误日志
error_log("API Cache Error: {$e->getMessage()}");
return $default;
}
}
Memcached缓存(分布式场景)
基础实现
<?php
class MemcachedCache {
private $memcached;
public function __construct($servers = [['127.0.0.1', 11211]]) {
$this->memcached = new Memcached();
$this->memcached->addServers($servers);
$this->memcached->setOption(Memcached::OPT_COMPRESSION, true);
}
public function get($key) {
return $this->memcached->get($key);
}
public function set($key, $value, $ttl = 3600) {
return $this->memcached->set($key, $value, $ttl);
}
}
最佳实践策略
缓存降级策略
<?php
class CacheStrategy {
// 阶梯缓存时间
const CACHE_TIERS = [
'high' => 60, // 高频率更新:1分钟
'medium' => 300, // 中频率更新:5分钟
'low' => 3600 // 低频率更新:1小时
];
// 根据接口类型选择缓存策略
public function getCacheTTL($apiType) {
switch ($apiType) {
case 'weather':
return self::CACHE_TIERS['medium'];
case 'stock':
return self::CACHE_TIERS['high'];
case 'country_code':
return self::CACHE_TIERS['low'];
default:
return 600; // 10分钟默认
}
}
}
双重缓存机制
<?php
class DualCache {
private $local; // 本地文件缓存
private $remote; // Redis缓存
public function __construct() {
$this->local = new FileCache();
$this->remote = new RedisCache();
}
public function get($key) {
// 1. 先查本地缓存(最快)
if ($data = $this->local->get($key)) {
return $data;
}
// 2. 再查Redis缓存
if ($data = $this->remote->get($key)) {
// 同步到本地
$this->local->set($key, $data, 60);
return $data;
}
return false;
}
public function set($key, $value, $ttl = 300) {
// 同时写入两级缓存
$this->remote->set($key, $value, $ttl);
$this->local->set($key, $value, min($ttl, 60));
}
}
缓存穿透防护
<?php
class CachePenetrationProtection {
public function getWithProtection($key, $callback, $ttl = 300) {
// 1. 使用布隆过滤器快速判断
if (!$this->bloomFilter->exists($key)) {
return null;
}
// 2. 互斥锁防止缓存击穿
$lockKey = "lock:{$key}";
if ($this->cache->get($key) === false) {
if ($this->lock($lockKey)) {
try {
$data = call_user_func($callback);
$this->cache->set($key, $data, $ttl);
return $data;
} finally {
$this->unlock($lockKey);
}
}
}
return $this->cache->get($key);
}
}
框架集成方案
Laravel示例
// config/cache.php
'api_cache' => [
'driver' => 'redis',
'connection' => 'default',
'prefix' => 'api_',
],
// 使用缓存
$weather = Cache::store('api_cache')->remember('weather', 300, function () {
return Http::get('https://api.weather.com')->json();
});
ThinkPHP示例
use think\facade\Cache;
// 配置
Cache::store('redis')->set($key, $data, 300);
// 获取
if (Cache::has($key)) {
return Cache::get($key);
}
缓存清理策略
<?php
class CacheCleaner {
// 定时清理过期缓存
public function cleanExpired() {
$files = glob('/tmp/cache/*.cache');
foreach ($files as $file) {
if (filemtime($file) + 3600 < time()) {
unlink($file);
}
}
}
// 按前缀批量清除
public function cleanByPrefix($prefix) {
$keys = $this->redis->keys("{$prefix}*");
if (!empty($keys)) {
$this->redis->del($keys);
}
}
// 缓存预热(加载常用数据)
public function warmup($apiList) {
foreach ($apiList as $api => $config) {
// 预请求并缓存
$data = $this->fetchApi($api);
$this->cache->set($api, $data, $config['ttl']);
}
}
}
建议
-
选择原则:
- 单机项目:文件缓存即可
- 中等项目:Redis
- 高并发:Redis + 本地缓存
-
缓存时间:
- 动态数据:30秒-5分钟
- 静态数据:1-24小时
- 极少变化:7天以上
-
异常处理:
- 必须包含降级策略
- 记录缓存失败日志
- 设置合理的过期时间
这样既保证了数据新鲜度,又提高了系统稳定性。