Back to symfony.com

Demo 7 of 10 · 2 min

Click any paragraph or press to highlight its code

Caching expensive work

The whole caching pattern (check if it's cached, compute if not, store the result) is one method call. The callback only runs on a cache miss; the next 10,000 requests get the stored value.

The killer detail: built-in stampede protection. When a popular entry expires, one request recomputes it while the others keep getting the old value. No thundering herd taking down your weather API at rush hour.

Storage is configuration, not code. Start with the filesystem and move to Redis when you grow, without touching your services. Tags, namespaces and a cache:clear command included.

<?phpnamespace App\Service;use Symfony\Contracts\Cache\CacheInterface;use Symfony\Contracts\Cache\ItemInterface;class WeatherForecast{    public function __construct(        private CacheInterface $cache,    ) {    }    public function getForecast(string $city): array    {        return $this->cache->get(            "forecast_$city",            function (ItemInterface $item) use ($city): array {                $item->expiresAfter(1800);                // this code only runs on a cache miss                return $this->callSlowWeatherApi($city);            },        );    }    private function callSlowWeatherApi(string $city): array    {        // ... a 2-second HTTP request to the weather provider    }}
framework:    cache:        # swap the storage backend with one line: filesystem        # (default), Redis, Memcached, APCu, a database, ...        app: cache.adapter.redis        default_redis_provider: 'redis://localhost'