本文目录导读:

在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)
选择合适的缓存方案时,要考虑:
- 数据更新频率
- 用户访问分布
- 系统资源限制
- 运维复杂度
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播