本文目录导读:

在PHP项目中缓存气象数据是减少API调用、提升性能的重要手段,以下是几种常见的实现方案,按复杂度从低到高排列:
文件缓存(简单直接)
<?php
class WeatherCache {
private $cacheDir = './cache/weather/';
private $cacheTime = 1800; // 30分钟缓存
public function getWeatherData($city) {
$cacheFile = $this->cacheDir . md5($city) . '.json';
// 检查缓存是否有效
if (file_exists($cacheFile) && time() - filemtime($cacheFile) < $this->cacheTime) {
return json_decode(file_get_contents($cacheFile), true);
}
// 调用真实API
$data = $this->fetchFromApi($city);
// 写入缓存
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0755, true);
}
file_put_contents($cacheFile, json_encode($data));
return $data;
}
private function fetchFromApi($city) {
// 实际API调用代码
$apiUrl = "https://api.weather.com/v1/location/{$city}";
$response = file_get_contents($apiUrl);
return json_decode($response, true);
}
}
Redis缓存(高性能推荐)
<?php
use Predis\Client;
class WeatherRedisCache {
private $redis;
private $ttl = 1800; // 30分钟过期
public function __construct() {
$this->redis = new Client([
'scheme' => 'tcp',
'host' => '127.0.0.1',
'port' => 6379,
]);
}
public function getWeather($city) {
$key = "weather:{$city}";
// 检查Redis缓存
if ($this->redis->exists($key)) {
return json_decode($this->redis->get($key), true);
}
// 从API获取
$data = $this->fetchWeather($city);
// 存入Redis
$this->redis->setex($key, $this->ttl, json_encode($data));
return $data;
}
private function fetchWeather($city) {
// API调用
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.openweathermap.org/data/2.5/weather?q={$city}&appid=YOUR_API_KEY");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
Memcached缓存(分布式场景)
<?php
class WeatherMemcachedCache {
private $memcached;
private $expiration = 1800;
public function __construct() {
$this->memcached = new Memcached();
$this->memcached->addServer('localhost', 11211);
}
public function getWeatherData($city) {
$key = "weather_data_{$city}";
// 尝试从缓存获取
$cachedData = $this->memcached->get($key);
if ($cachedData !== false) {
return $cachedData;
}
// 获取新数据
$data = $this->callWeatherApi($city);
// 存入缓存
$this->memcached->set($key, $data, $this->expiration);
return $data;
}
}
数据库缓存(持久化方案)
-- 创建缓存表
CREATE TABLE weather_cache (
id INT PRIMARY KEY AUTO_INCREMENT,
city VARCHAR(100) UNIQUE,
weather_data JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_city (city)
);
<?php
class WeatherDBCache {
private $db;
private $cacheTime = 1800;
public function getWeather($city) {
// 查询数据库缓存
$stmt = $this->db->prepare("SELECT weather_data, updated_at FROM weather_cache WHERE city = ?");
$stmt->execute([$city]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
$updatedAt = strtotime($result['updated_at']);
if (time() - $updatedAt < $this->cacheTime) {
return json_decode($result['weather_data'], true);
}
}
// 获取新数据
$data = $this->fetchFromApi($city);
// 更新数据库
$jsonData = json_encode($data);
if ($result) {
$updateStmt = $this->db->prepare("UPDATE weather_cache SET weather_data = ? WHERE city = ?");
$updateStmt->execute([$jsonData, $city]);
} else {
$insertStmt = $this->db->prepare("INSERT INTO weather_cache (city, weather_data) VALUES (?, ?)");
$insertStmt->execute([$city, $jsonData]);
}
return $data;
}
}
多级缓存策略(最优化)
<?php
class MultiLevelWeatherCache {
private $redis;
private $fileCache;
private $config = [
'file_ttl' => 3600, // 文件缓存1小时
'redis_ttl' => 1800, // Redis缓存30分钟
'db_ttl' => 7200 // 数据库缓存2小时
];
public function getWeatherData($city, $forceRefresh = false) {
$key = "weather_{$city}";
// 1. 检查Redis缓存(最快)
if (!$forceRefresh) {
$data = $this->getFromRedis($key);
if ($data) return $data;
}
// 2. 检查文件缓存
if (!$forceRefresh) {
$data = $this->getFromFile($key);
if ($data) {
// 异步更新Redis
$this->setRedisCache($key, $data);
return $data;
}
}
// 3. 从API获取
$data = $this->fetchFromApi($city);
// 4. 更新所有缓存层
$this->setRedisCache($key, $data);
$this->setFileCache($key, $data);
return $data;
}
private function getFromRedis($key) {
// Redis获取逻辑
}
private function getFromFile($key) {
// 文件缓存获取
}
private function setRedisCache($key, $data) {
// 设置Redis缓存
}
private function setFileCache($key, $data) {
// 设置文件缓存
}
}
懒加载与预缓存策略
<?php
class WeatherPreloadCache {
// 热门城市列表
private $hotCities = ['北京', '上海', '广州', '深圳', '杭州'];
public function preloadHotCities() {
// 系统启动或定时任务预加载热门城市数据
foreach ($this->hotCities as $city) {
$this->getWeatherData($city);
}
}
public function getWeatherData($city, $lazyLoad = true) {
// 懒加载:仅在请求时获取
if ($lazyLoad) {
return $this->lazyGet($city);
}
// 提前加载
return $this->fetchFromApi($city);
}
private function lazyGet($city) {
$cache = new WeatherRedisCache();
return $cache->getWeather($city);
}
}
最佳实践建议
缓存时间设置参考
// 根据不同数据类型设置不同缓存时间
$cacheConfig = [
'current_weather' => 1800, // 当前天气 30分钟
'hourly_forecast' => 3600, // 小时预报 1小时
'daily_forecast' => 7200, // 日报预报 2小时
'weekly_forecast' => 86400, // 周预报 24小时
'air_quality' => 3600, // 空气质量 1小时
];
错误处理与降级
public function getWeatherWithFallback($city) {
try {
// 尝试从缓存获取
return $this->getFromCache($city);
} catch (Exception $e) {
// 缓存失败,从API获取
$data = $this->fetchFromApi($city);
// 尝试写入缓存(非关键操作)
try {
$this->setCache($city, $data);
} catch (Exception $cacheError) {
// 记录日志但不影响主流程
error_log("Cache write failed: " . $cacheError->getMessage());
}
return $data;
}
}
监控缓存命中率
class WeatherCacheMonitor {
private static $hitCount = 0;
private static $missCount = 0;
public function recordHit() {
self::$hitCount++;
}
public function recordMiss() {
self::$missCount++;
}
public function getHitRate() {
$total = self::$hitCount + self::$missCount;
return $total > 0 ? (self::$hitCount / $total) * 100 : 0;
}
}
推荐方案
对于大多数PHP项目:
- 小项目:使用文件缓存 + Redis(如果可用)
- 中型项目:Redis缓存 + 数据库持久化
- 大型项目:多级缓存(Redis + 文件 + CDN)
- 高并发场景:Redis集群 + 本地缓存(APCu)
选择合适的缓存方案时,要考虑:
- 数据更新频率
- 用户访问分布
- 系统资源限制
- 运维复杂度