See More

|null} * @psalm-type MatchingEncoderDetector = \Closure(Context, mixed): MatchedEncoderInfo * * @psalm-suppress UnusedClass * * @implements XmlEncoder */ final readonly class MatchingValueEncoder implements XmlEncoder { /** * @param MatchingEncoderDetector $encoderDetector * @param XmlEncoder $defaultEncoder */ public function __construct( private Closure $encoderDetector, private XmlEncoder $defaultEncoder, ) { } public function iso(Context $context): Iso { $defaultIso = $this->defaultEncoder->iso($context); return new Iso( to: fn (mixed $value): string => $this->to($context, $value), /** * @param string|Element $value */ from: static fn (string|Element $value): mixed => $defaultIso->from($value), ); } private function to(Context $context, mixed $value): string { $matchedEncoderInfo = ($this->encoderDetector)($context, $value); [$context, $encoder] = match(true) { $matchedEncoderInfo instanceof Context => [$matchedEncoderInfo, $this->defaultEncoder], default => [$matchedEncoderInfo[0], $matchedEncoderInfo[1] ?? $this->defaultEncoder], }; /** @psalm-suppress RedundantConditionGivenDocblockType - This gives better feedback to people using this encoder */ // Ensure that the encoderDetector returns valid data. invariant($context instanceof Context, 'The MatchingValueEncoder::$encoderDetector callable must return a Context or an array with a Context as first element.'); invariant($encoder instanceof XmlEncoder, 'The MatchingValueEncoder::$encoderDetector callable must return a Context or an array with a Context as first element and an optional XmlEncoder as second element.'); return $encoder->iso($context)->to($value); } }