You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在不提供回调函数的情况下从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:10:33