本文目录导读:

我来为你详细讲解PHP中如何实现适配器模式切换缓存驱动,这是一个非常实用的设计模式应用场景。
基础架构设计
1 缓存接口定义
<?php
namespace App\Cache;
interface CacheInterface
{
public function get(string $key): mixed;
public function set(string $key, mixed $value, int $ttl = null): bool;
public function delete(string $key): bool;
public function clear(): bool;
public function has(string $key): bool;
}
2 Redis缓存适配器
<?php
namespace App\Cache\Adapter;
use App\Cache\CacheInterface;
use Redis;
class RedisCache implements CacheInterface
{
private Redis $client;
private string $prefix;
public function __construct(array $config)
{
$this->client = new Redis();
$this->client->connect($config['host'], $config['port']);
if (isset($config['password'])) {
$this->client->auth($config['password']);
}
$this->prefix = $config['prefix'] ?? 'app:';
}
private function generateKey(string $key): string
{
return $this->prefix . $key;
}
public function get(string $key): mixed
{
$value = $this->client->get($this->generateKey($key));
return $value === false ? null : unserialize($value);
}
public function set(string $key, mixed $value, int $ttl = null): bool
{
$value = serialize($value);
if ($ttl) {
return $this->client->setex($this->generateKey($key), $ttl, $value);
}
return $this->client->set($this->generateKey($key), $value);
}
public function delete(string $key): bool
{
return $this->client->del($this->generateKey($key)) > 0;
}
public function clear(): bool
{
$prefix = $this->prefix;
$keys = $this->client->keys($prefix . '*');
if (empty($keys)) return true;
return $this->client->del($keys) > 0;
}
public function has(string $key): bool
{
return $this->client->exists($this->generateKey($key));
}
}
3 Memcached缓存适配器
<?php
namespace App\Cache\Adapter;
use App\Cache\CacheInterface;
use Memcached;
class MemcachedCache implements CacheInterface
{
private Memcached $client;
private string $prefix;
public function __construct(array $config)
{
$this->client = new Memcached();
$this->client->addServer($config['host'], $config['port']);
$this->prefix = $config['prefix'] ?? 'app:';
}
private function generateKey(string $key): string
{
return $this->prefix . $key;
}
public function get(string $key): mixed
{
$value = $this->client->get($this->generateKey($key));
return $value === false ? null : unserialize($value);
}
public function set(string $key, mixed $value, int $ttl = null): bool
{
$value = serialize($value);
return $this->client->set($this->generateKey($key), $value, $ttl ?? 0);
}
public function delete(string $key): bool
{
return $this->client->delete($this->generateKey($key));
}
public function clear(): bool
{
return $this->client->flush();
}
public function has(string $key): bool
{
$value = $this->client->get($this->generateKey($key));
return $value !== false;
}
}
4 文件缓存适配器
<?php
namespace App\Cache\Adapter;
use App\Cache\CacheInterface;
class FileCache implements CacheInterface
{
private string $cacheDir;
private string $prefix;
public function __construct(array $config)
{
$this->cacheDir = $config['path'] ?? sys_get_temp_dir() . '/cache';
$this->prefix = $config['prefix'] ?? 'app_';
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0777, true);
}
}
private function getFilePath(string $key): string
{
return $this->cacheDir . '/' . $this->prefix . md5($key) . '.cache';
}
public function get(string $key): mixed
{
$file = $this->getFilePath($key);
if (!file_exists($file)) return null;
$data = unserialize(file_get_contents($file));
if ($data['expires'] !== 0 && $data['expires'] < time()) {
$this->delete($key);
return null;
}
return $data['value'];
}
public function set(string $key, mixed $value, int $ttl = null): bool
{
$file = $this->getFilePath($key);
$data = [
'value' => $value,
'expires' => $ttl ? time() + $ttl : 0
];
return file_put_contents($file, serialize($data)) !== false;
}
public function delete(string $key): bool
{
$file = $this->getFilePath($key);
if (file_exists($file)) {
return unlink($file);
}
return true;
}
public function clear(): bool
{
$files = glob($this->cacheDir . '/' . $this->prefix . '*.cache');
foreach ($files as $file) {
unlink($file);
}
return true;
}
public function has(string $key): bool
{
return $this->get($key) !== null;
}
}
5 数据库缓存适配器
<?php
namespace App\Cache\Adapter;
use App\Cache\CacheInterface;
use PDO;
class DatabaseCache implements CacheInterface
{
private PDO $pdo;
private string $table;
public function __construct(array $config)
{
$dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8',
$config['host'], $config['database']);
$this->pdo = new PDO($dsn, $config['username'], $config['password']);
$this->table = $config['table'] ?? 'cache';
$this->createTableIfNotExists();
}
private function createTableIfNotExists(): void
{
$sql = "CREATE TABLE IF NOT EXISTS {$this->table} (
cache_key VARCHAR(255) PRIMARY KEY,
cache_value LONGTEXT,
expires_at INT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
$this->pdo->exec($sql);
}
public function get(string $key): mixed
{
$stmt = $this->pdo->prepare("SELECT * FROM {$this->table} WHERE cache_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) return null;
if ($row['expires_at'] !== null && $row['expires_at'] < time()) {
$this->delete($key);
return null;
}
return unserialize($row['cache_value']);
}
public function set(string $key, mixed $value, int $ttl = null): bool
{
$expires = $ttl ? time() + $ttl : null;
$value = serialize($value);
$sql = "INSERT INTO {$this->table} (cache_key, cache_value, expires_at)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
cache_value = VALUES(cache_value),
expires_at = VALUES(expires_at)";
$stmt = $this->pdo->prepare($sql);
return $stmt->execute([$key, $value, $expires]);
}
public function delete(string $key): bool
{
$stmt = $this->pdo->prepare("DELETE FROM {$this->table} WHERE cache_key = ?");
return $stmt->execute([$key]);
}
public function clear(): bool
{
return $this->pdo->exec("TRUNCATE TABLE {$this->table}") !== false;
}
public function has(string $key): bool
{
return $this->get($key) !== null;
}
}
缓存管理器(工厂类)
<?php
namespace App\Cache;
use App\Cache\Adapter\RedisCache;
use App\Cache\Adapter\MemcachedCache;
use App\Cache\Adapter\FileCache;
use App\Cache\Adapter\DatabaseCache;
use InvalidArgumentException;
class CacheManager
{
private array $configs;
private array $instances = [];
public function __construct(array $configs)
{
$this->configs = $configs;
}
public function driver(string $name = null): CacheInterface
{
$name = $name ?: $this->configs['default'];
$config = $this->configs['drivers'][$name] ?? null;
if (!$config) {
throw new InvalidArgumentException("Cache driver [{$name}] not found");
}
if (!isset($this->instances[$name])) {
$this->instances[$name] = $this->createDriver($config);
}
return $this->instances[$name];
}
private function createDriver(array $config): CacheInterface
{
$type = $config['type'];
return match ($type) {
'redis' => new RedisCache($config),
'memcached' => new MemcachedCache($config),
'file' => new FileCache($config),
'database' => new DatabaseCache($config),
default => throw new InvalidArgumentException("Unsupported cache type: {$type}")
};
}
}
配置示例
// config/cache.php
return [
'default' => env('CACHE_DRIVER', 'redis'),
'drivers' => [
'redis' => [
'type' => 'redis',
'host' => '127.0.0.1',
'port' => 6379,
'password' => null,
'prefix' => 'myapp:',
],
'memcached' => [
'type' => 'memcached',
'host' => '127.0.0.1',
'port' => 11211,
'prefix' => 'myapp:',
],
'file' => [
'type' => 'file',
'path' => storage_path('/cache'),
'prefix' => 'myapp_',
],
'database' => [
'type' => 'database',
'host' => '127.0.0.1',
'database' => 'mydb',
'username' => 'root',
'password' => '',
'table' => 'cache',
],
],
];
门面(Facade)模式
<?php
namespace App\Facades;
use App\Cache\CacheManager;
class Cache
{
private static ?CacheManager $manager = null;
public static function init(array $configs): void
{
self::$manager = new CacheManager($configs);
}
public static function put(string $key, mixed $value, int $ttl = null): bool
{
return self::driver()->set($key, $value, $ttl);
}
public static function get(string $key, mixed $default = null): mixed
{
$value = self::driver()->get($key);
return $value ?? $default;
}
public static function remember(string $key, int $ttl, callable $callback): mixed
{
if ($value = self::get($key)) {
return $value;
}
$value = $callback();
self::put($key, $value, $ttl);
return $value;
}
public static function forget(string $key): bool
{
return self::driver()->delete($key);
}
public static function flush(): bool
{
return self::driver()->clear();
}
public static function has(string $key): bool
{
return self::driver()->has($key);
}
public static function driver(string $name = null): CacheInterface
{
return self::$manager->driver($name);
}
}
使用示例
<?php
// 初始化配置
$configs = [
'default' => 'redis',
'drivers' => [
'redis' => [
'type' => 'redis',
'host' => '127.0.0.1',
'port' => 6379,
],
'file' => [
'type' => 'file',
'path' => '/tmp/cache',
],
],
];
Cache::init($configs);
// 使用默认驱动(Redis)
Cache::put('user:1', ['name' => 'John', 'age' => 30], 3600);
$user = Cache::get('user:1');
// 切换驱动(临时使用文件缓存)
Cache::driver('file')->set('page:about', '<html>...</html>', 7200);
$page = Cache::driver('file')->get('page:about');
// 使用remember模式
$data = Cache::remember('trending:posts', 1800, function () {
// 从数据库查询热门文章
return DB::table('posts')->where('views', '>', 1000)->get()->toArray();
});
// 删除缓存
Cache::forget('user:1');
// 清空缓存
Cache::flush();
生产环境的高级配置
<?php
namespace App\Cache;
class AdvancedCacheManager extends CacheManager
{
private array $stats = [];
public function driver(string $name = null): CacheInterface
{
$driver = parent::driver($name);
// 添加统计装饰器
return new StatisticsCache($driver, $this->stats);
}
public function getStats(): array
{
return $this->stats;
}
}
// 统计装饰器
class StatisticsCache implements CacheInterface
{
private CacheInterface $driver;
private array &$stats;
public function __construct(CacheInterface $driver, array &$stats)
{
$this->driver = $driver;
$this->stats = &$stats;
}
public function get(string $key): mixed
{
$start = microtime(true);
$value = $this->driver->get($key);
$this->record('get', microtime(true) - $start);
return $value;
}
public function set(string $key, mixed $value, int $ttl = null): bool
{
$start = microtime(true);
$result = $this->driver->set($key, $value, $ttl);
$this->record('set', microtime(true) - $start);
return $result;
}
private function record(string $operation, float $duration): void
{
$this->stats[$operation] = $this->stats[$operation] ?? [
'count' => 0,
'total_time' => 0
];
$this->stats[$operation]['count']++;
$this->stats[$operation]['total_time'] += $duration;
}
// 其他方法委托给内部驱动
public function delete(string $key): bool { return $this->driver->delete($key); }
public function clear(): bool { return $this->driver->clear(); }
public function has(string $key): bool { return $this->driver->has($key); }
}
这个适配器模式的设计具有以下优势:
- 松耦合:业务代码不依赖具体缓存实现
- 易扩展:添加新驱动只需实现CacheInterface接口
- 灵活切换:通过配置或运行时动态切换缓存驱动
- 统计监控:可以方便地添加监控和统计功能
- 统一接口:所有驱动提供一致的API
通过这种设计,你可以轻松地在不同缓存系统之间切换,而无需修改业务代码。
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播