Repository: symfony/symfony
File: src/Symfony/Component/HttpFoundation/AcceptHeader.php (PHP)

Code before:
        }
    }

    /**
     * Sorts candidates by specificity, quality, parameter count, and original order.
     *
     * @param AcceptHeaderItem[] $candidates
     */
    private function sortCandidates(array &$candidates, AcceptHeaderItem $queryItem): void
    {
        usort($candidates, function (AcceptHeaderItem $a, AcceptHeaderItem $b) use ($queryItem) {
            $specificityA = $this->getSpecificity($a, $queryItem);
            $specificityB = $this->getSpecificity($b, $queryItem);
            if ($specificityA !== $specificityB) {
                return $specificityB <=> $specificityA;
            }
            if ($a->getQuality() !== $b->getQuality()) {
                return $b->getQuality() <=> $a->getQuality();
            }
            $parameterCountA = \count($this->getMediaParams($a));
            $parameterCountB = \count($this->getMediaParams($b));
            if ($parameterCountA !== $parameterCountB) {
                return $parameterCountB <=> $parameterCountA;
            }

            return $a->getIndex() <=> $b->getIndex();
        });
    }

    /**
     * Builds a canonical string representation of attributes.
     *
     * @param array<string, mixed> $attributes
     */
    private function buildCanonicalParams(array $attributes): string
    {
        $normalizedAttributes = [];
        foreach ($attributes as $name => $value) {
            $lowerName = strtolower($name);
            if ('q' === $lowerName) {
                continue;
            }
            $normalizedAttributes[$lowerName] = $value;
        }
        ksort($normalizedAttributes);
        $parameterParts = [];
        foreach ($normalizedAttributes as $name => $value) {
            if (null === $value) {
                $parameterParts[] = $name;
            } else {
                $quotedValue = \is_string($value) && str_contains($value, ' ') ? '"'.addslashes($value).'"' : $value;

Review comment (refactor):
To all I know, the `<=>` comparison allows to simplify two custom checks into a check on an array of values, with the most important comparison criteria sorted first:
```suggestion
                $comparison = [$this->getSpecificity($b, $queryItem), $b->getQuality(), count($this->getMediaParams($b)] <=> [$this->getSpecificity($a, $queryItem), $a->getQuality(), count($this->getMediaParams($a)];
                if ($comparison !== 0) {
                    return $comparison;
                }
                return $a->getIndex() <=> $b->getIndex();
            }
```

Code after:
            $quotedValue = \is_string($value) && preg_match('/[\s;,=]/', $value) ? '"'.addcslashes($value, '"\\').'"' : $value;

            $parts[] = $name.'='.$quotedValue;
        }

        return $item->getValue().($parts ? ';'.implode(';', $parts) : '');
    }

    /**
     * Checks if a given header item (range) matches a queried item (value).
     *
     * @param AcceptHeaderItem $rangeItem The item from the Accept header (e.g., text/*;format=flowed)
     * @param AcceptHeaderItem $queryItem The item being queried (e.g., text/plain;format=flowed;charset=utf-8)
     */
    private function matches(AcceptHeaderItem $rangeItem, AcceptHeaderItem $queryItem): bool
    {
        $rangeValue = strtolower($rangeItem->getValue());
        $queryValue = strtolower($queryItem->getValue());

        // Handle universal wildcard ranges
        if ('*' === $rangeValue || '*/*' === $rangeValue) {
            return $this->rangeParametersMatch($rangeItem, $queryItem);
        }

        // Queries for '*' only match wildcard ranges (handled above)
        if ('*' === $queryValue) {
            return false;
        }

        // Ensure media vs. non-media consistency
        $isQueryMedia = str_contains($queryValue, '/');
        $isRangeMedia = str_contains($rangeValue, '/');

        if ($isQueryMedia !== $isRangeMedia) {
            return false;
        }

        // Non-media: exact match only (wildcards handled above)
        if (!$isQueryMedia) {
            return $rangeValue === $queryValue && $this->rangeParametersMatch($rangeItem, $queryItem);
        }

        // Media type: type/subtype with wildcards
        [$queryType, $querySubtype] = explode('/', $queryValue, 2);
        [$rangeType, $rangeSubtype] = explode('/', $rangeValue, 2) + [1 => '*'];

        if ('*' !== $rangeType && $rangeType !== $queryType) {
            return false;
        }

        if ('*' !== $rangeSubtype && $rangeSubtype !== $querySubtype) {