Repository: symfony/symfony
File: src/Symfony/Component/Console/Attribute/Ask.php (PHP)

Code before:

            if ($reflection->isParameter() && !\in_array($input->getArgument($name), [null, []], true)) {
                return;
            }

            $question = new Question($self->question, $self->default);
            $question->setHidden($self->hidden);
            $question->setMultiline($self->multiline);
            $question->setTrimmable($self->trimmable);
            $question->setTimeout($self->timeout);

            if (!$self->validator && $reflection->isProperty()) {
                $self->validator = function (mixed $value) use ($reflection): mixed {
                    return $this->{$reflection->getName()} = $value;
                };
            }

            $question->setValidator($self->validator);
            $question->setMaxAttempts($self->maxAttempts);

            if ($reflection->isBackedEnumType()) {
                /** @var class-string<\BackedEnum> $backedType */
                $backedType = $reflection->getType()->getName();
                $question->setNormalizer(fn (string|int $value) => $backedType::tryFrom($value) ?? throw InvalidArgumentException::fromEnumValue($reflection->getName(), $value, array_map(fn (\BackedEnum $enum): string|int => $enum->value, $backedType::cases())));
            } elseif ($reflection->isArrayType()) {
                $question->setNormalizer(fn (string $value) => array_values(array_filter(explode(' ', $value))));
            }

            $value = $io->askQuestion($question);

            if (null === $value && !$reflection->isNullable()) {
                return;
            }

            if ($reflection->isProperty()) {
                $this->{$reflection->getName()} = $value;
            } else {
                $input->setArgument($name, $value);
            }
        };

        return $self;
    }

    /**
     * @internal
     */
    public function getFunction(object $instance): \ReflectionFunction
    {
        return new \ReflectionFunction($this->closure->bindTo($instance, $instance::class));
    }

Review comment (performance):
I am wondering if being able to configure the separator via constructor argument would be beneficial with little added complexity in contrast to hard-coding it or if it is not really necessary.

(Though I have no real-live experience with such cases where multiple values would be requested.)

Code after:

        $type = $reflection->getType();

        if (!$type instanceof \ReflectionNamedType) {
            throw new LogicException(\sprintf('The %s "$%s" of "%s" must have a named type. Untyped, Union or Intersection types are not supported for interactive questions.', $reflection->getMemberName(), $name, $reflection->getSourceName()));
        }

        $self->closure = function (SymfonyStyle $io, InputInterface $input) use ($self, $reflection, $name, $type) {
            if ($reflection->isProperty() && isset($this->{$reflection->getName()})) {
                return;
            }

            if ($reflection->isParameter() && !\in_array($input->getArgument($name), [null, []], true)) {
                return;
            }

            if ('bool' === $type->getName()) {
                $self->default ??= false;

                if (!\is_bool($self->default)) {
                    throw new LogicException(\sprintf('The "%s::$default" value for the %s "$%s" of "%s" must be a boolean.', self::class, $reflection->getMemberName(), $name, $reflection->getSourceName()));
                }

                $question = new ConfirmationQuestion($self->question, $self->default);
            } else {
                $question = new Question($self->question, $self->default);
            }
            $question->setHidden($self->hidden);
            $question->setMultiline($self->multiline);
            $question->setTrimmable($self->trimmable);
            $question->setTimeout($self->timeout);

            if (!$self->validator && $reflection->isProperty() && 'array' !== $type->getName()) {
                $self->validator = function (mixed $value) use ($reflection): mixed {
                    return $this->{$reflection->getName()} = $value;
                };
            }

            $question->setValidator($self->validator);
            $question->setMaxAttempts($self->maxAttempts);

            if ($self->normalizer) {
                $question->setNormalizer($self->normalizer);
            } elseif (is_subclass_of($type->getName(), \BackedEnum::class)) {
                /** @var class-string<\BackedEnum> $backedType */
                $backedType = $reflection->getType()->getName();
                $question->setNormalizer(fn (string|int $value) => $backedType::tryFrom($value) ?? throw InvalidArgumentException::fromEnumValue($reflection->getName(), $value, array_column($backedType::cases(), 'value')));
            }

            if ('array' === $type->getName()) {
                $value = [];