Repository: symfony/symfony
File: src/Symfony/Component/HttpKernel/EventListener/CacheAttributeListener.php (PHP)

Code before:

    /**
     * Handles HTTP validation headers.
     */
    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void
    {
        $request = $event->getRequest();

        if (!$attributes = $request->attributes->get('_cache') ?? $event->getAttributes(Cache::class)) {
            return;
        }

        $request->attributes->set('_cache', $attributes);
        $response = null;
        $lastModified = null;
        $etag = null;

        /** @var Cache[] $attributes */
        foreach ($attributes as $cache) {
            if (null !== $cache->lastModified) {
                $lastModified = $this->evaluate($cache->lastModified, $request, $arguments ??= $event->getNamedArguments());
                ($response ??= new Response())->setLastModified($lastModified);
            }

            if (null !== $cache->etag) {
                $etag = hash('sha256', $this->evaluate($cache->etag, $request, $arguments ??= $event->getNamedArguments()));
                ($response ??= new Response())->setEtag($etag);
            }
        }

        if ($response?->isNotModified($request)) {
            $event->setController(static fn () => $response);
            $event->stopPropagation();

            return;
        }

        if (null !== $etag) {
            $this->etags[$request] = $etag;
        }
        if (null !== $lastModified) {
            $this->lastModified[$request] = $lastModified;
        }
    }

    /**
     * Modifies the response to apply HTTP cache headers when needed.
     */
    public function onKernelResponse(ResponseEvent $event): void
    {
        $request = $event->getRequest();

Review comment (performance):
wouldn't it make more sense to do something like this?

```suggestion
                $etag = hash('sha256', $this->getExpressionLanguage()->evaluate($cache->etag, $variables ??= $this->getVariables($request, $event));
```

Code after:

    /**
     * Handles HTTP validation headers.
     */
    public function onKernelControllerArguments(ControllerArgumentsEvent $event): void
    {
        $request = $event->getRequest();

        if (!$attributes = $request->attributes->get('_cache') ?? $event->getAttributes(Cache::class)) {
            return;
        }

        $request->attributes->set('_cache', $attributes);
        $response = null;
        $lastModified = null;
        $etag = null;
        $variables = null;

        /** @var Cache[] $attributes */
        foreach ($attributes as $cache) {
            if (null !== $cache->lastModified) {
                $lastModified = $this->getExpressionLanguage()->evaluate($cache->lastModified, $variables ??= $this->getVariables($request, $event));
                ($response ??= new Response())->setLastModified($lastModified);
            }

            if (null !== $cache->etag) {
                $etag = hash('sha256', $this->getExpressionLanguage()->evaluate($cache->etag, $variables ??= $this->getVariables($request, $event)));
                ($response ??= new Response())->setEtag($etag);
            }
        }

        if ($response?->isNotModified($request)) {
            $event->setController(static fn () => $response);
            $event->stopPropagation();

            return;
        }

        if (null !== $etag) {
            $this->etags[$request] = $etag;
        }
        if (null !== $lastModified) {
            $this->lastModified[$request] = $lastModified;
        }
    }

    /**
     * Modifies the response to apply HTTP cache headers when needed.
     */
    public function onKernelResponse(ResponseEvent $event): void
    {