如何在不提供回调函数的情况下从Symfony缓存中获取值?
解决方案:无需直接使用适配器实现Symfony缓存条目查询
针对你的场景,有以下几种符合最佳实践的方案,无需直接依赖具体缓存适配器:
方案1:使用PSR-6标准的CacheItemPoolInterface
Symfony所有缓存适配器都实现了PSR-6的CacheItemPoolInterface,这个接口原生支持无回调获取缓存条目,完全匹配你的需求流程:
- 批量获取多个产品的缓存条目
- 筛选出未命中的产品ID
- 批量请求API获取缺失数据
- 批量写入缓存
示例代码:
use Psr\Cache\CacheItemPoolInterface; class ProductCacheService { public function __construct(private CacheItemPoolInterface $cachePool) {} public function getProducts(array $productIds): array { // 生成每个产品对应的缓存键 $cacheKeys = array_map(fn($id) => "product_{$id}", $productIds); // 批量获取缓存条目(无回调) $cacheItems = $this->cachePool->getItems($cacheKeys); $cachedProducts = []; $missingIds = []; // 遍历条目区分已缓存和未缓存的产品 foreach ($cacheItems as $key => $item) { $productId = str_replace('product_', '', $key); if ($item->isHit()) { $cachedProducts[$productId] = $item->get(); } else { $missingIds[] = $productId; } } // 批量请求API获取缺失产品数据 if (!empty($missingIds)) { $newProducts = $this->fetchProductsFromApi($missingIds); // 批量写入缓存 foreach ($newProducts as $id => $data) { $item = $this->cachePool->getItem("product_{$id}"); $item->set($data); $this->cachePool->saveDeferred($item); } $this->cachePool->commit(); $cachedProducts = array_merge($cachedProducts, $newProducts); } // 按原始请求顺序返回结果 return array_map(fn($id) => $cachedProducts[$id], $productIds); } private function fetchProductsFromApi(array $productIds): array { // 实现你的API批量请求逻辑 return []; } }
方案2:封装CacheInterface添加查询能力
如果项目中必须统一使用Symfony\Contracts\Cache\CacheInterface,可以通过装饰器模式封装一个扩展类,添加无回调查询方法:
use Symfony\Contracts\Cache\CacheInterface; use Psr\Cache\CacheItemPoolInterface; class CacheQueryDecorator implements CacheInterface { public function __construct( private CacheInterface $cache, private CacheItemPoolInterface $cachePool ) {} // 委托原CacheInterface的get方法 public function get(string $key, callable $callback, float $beta = null, array &$metadata = null): mixed { return $this->cache->get($key, $callback, $beta, $metadata); } // 自定义批量查询方法 public function getCachedItems(array $keys): array { $items = $this->cachePool->getItems($keys); $result = []; foreach ($items as $key => $item) { $result[$key] = $item->isHit() ? $item->get() : null; } return $result; } }
之后在服务配置中把这个装饰器注册为CacheInterface的实现,即可在业务代码中注入CacheInterface同时使用自定义查询方法。
方案3:不推荐的回调 hack(仅作参考)
虽然可以通过在回调中标记未命中条目实现需求,但会触发每个未缓存条目的回调逻辑,性能和代码可读性都很差,不适合批量场景,因此不推荐使用。
总结
最简洁且符合标准的方案是直接使用CacheItemPoolInterface,它完全贴合你的预期逻辑,不需要绕过Symfony契约,同时遵循PSR缓存标准,是最佳实践。
内容的提问来源于stack exchange,提问作者mscho
相关产品推荐
相关产品推荐

