Skip to content

Upgrading symfony/console 7 to 8

Breakingv7.4.22 → v8.1.10Breaking3Security1Platform1Deprecated1New28Changed6Fixed69Other3

Fetching 31 releases from GitHub…30 / 31
BreakingUpgrade verdict

3 breaking changes and a platform requirement change and a security fix.

  • The old add() methods on Application are gone.
  • Removes deprecated code.
  • Methods now declare return types, which can break subclasses that omit them.
  • This version needs PHP 8.4 or newer.
Top 5 of 6 that need code or config changes

PHP requirement changed in v8.1.0-BETA1: >=8.2 → >=8.4.1.

Breaking3
Removes the deprecated Application::add() methods.
Application::add()
Removes deprecated code.
Enforces return types on all components.
Security1
Strips terminal control characters from displayed file names.
Platform1
Bumps Symfony 8 to require PHP >= 8.4.
Deprecated1
Deprecates combining incompatible mode flags in InputArgument and InputOption.
InputArgumentInputOption

Generated by DepDelta from published PHP source. Not mixed with prose notes.

  • removed: method Application.add(Command $command): ?Command
  • changed: constructor Application(string $name = …, string $version = …) → constructor Application(string $name = …, string $version = …, ?ContainerInterface $container = …)
  • added: class ConsoleBundle extends AbstractBundle
  • added: const ConsoleEvents.QUESTION_ANSWERED
  • added: method Application.getArgumentResolver(): ?ArgumentResolverInterface
  • added: method Application.getDispatcher(): ?EventDispatcherInterface
  • added: method Application.setArgumentResolver(ArgumentResolverInterface $argumentResolver): void
  • added: method ConsoleBundle.build(ContainerBuilder $container): void
  • added: method ConsoleBundle.getPath(): string
  • added: method ConsoleBundle.loadExtension(array $config, ContainerConfigurator $configurator, ContainerBuilder $container): void
  • added: static method Terminal.setITerm2ImagesSupport(?bool $supported): void
  • added: static method Terminal.setKittyGraphicsSupport(?bool $supported): void
  • added: static method Terminal.supportsITerm2Images(): bool
  • added: static method Terminal.supportsImageProtocol(): bool
  • added: static method Terminal.supportsKittyGraphics(): bool
  • added: class TraceableArgumentResolver implements ArgumentResolverInterface
  • added: constructor ArgumentResolver(iterable $argumentValueResolvers = …, ?ContainerInterface $namedResolvers = …)
  • added: constructor TraceableArgumentResolver(ArgumentResolverInterface $resolver, Stopwatch $stopwatch)
  • added: final class ArgumentResolver implements ArgumentResolverInterface
  • added: interface ArgumentResolverInterface
  • added: method ArgumentResolver.getArguments(InputInterface $input, callable $command, ?\ReflectionFunctionAbstract $reflector = …): array
  • added: method ArgumentResolverInterface.getArguments(InputInterface $input, callable $command, ?\ReflectionFunctionAbstract $reflector = …): array
  • added: method TraceableArgumentResolver.getArguments(InputInterface $input, callable $command, ?\ReflectionFunctionAbstract $reflector = …): array
  • added: static method ArgumentResolver.getDefaultArgumentValueResolvers(): iterable
  • added: constructor ResolverNotFoundException(string $name, array $alternatives = …)
  • added: final class NearMissValueResolverException extends \RuntimeException
  • added: final class ResolverNotFoundException extends \RuntimeException
  • added: constructor DateTimeValueResolver(?ClockInterface $clock = …)
  • added: constructor MapInputValueResolver(ValueResolverInterface $builtinTypeResolver, ValueResolverInterface $backedEnumResolver, ValueResolverInterface $dateTimeResolver, ?ValidatorInterface $validator = …)
  • added: constructor ServiceValueResolver(ContainerInterface $container)
  • added: constructor TraceableValueResolver(ValueResolverInterface $inner, Stopwatch $stopwatch)
  • added: final class BackedEnumValueResolver implements ValueResolverInterface
  • added: final class BuiltinTypeValueResolver implements ValueResolverInterface
  • added: final class DateTimeValueResolver implements ValueResolverInterface
  • added: final class DefaultValueResolver implements ValueResolverInterface
  • added: final class InputFileValueResolver implements ValueResolverInterface
  • added: final class MapInputValueResolver implements ValueResolverInterface
  • added: final class ServiceValueResolver implements ValueResolverInterface
  • added: final class TraceableValueResolver implements ValueResolverInterface
  • added: final class UidValueResolver implements ValueResolverInterface
  • added: final class VariadicValueResolver implements ValueResolverInterface
  • added: interface ValueResolverInterface
  • added: method BackedEnumValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method BuiltinTypeValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method DateTimeValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method DefaultValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method InputFileValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method MapInputValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method ServiceValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method TraceableValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method UidValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method ValueResolverInterface.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • added: method VariadicValueResolver.resolve(string $argumentName, InputInterface $input, ReflectionMember $member): iterable
  • removed: method Argument.resolveValue(InputInterface $input): mixed
  • removed: method MapInput.resolveValue(InputInterface $input): object
  • removed: method Option.resolveValue(InputInterface $input): mixed
  • changed: class AsCommand → final class AsCommand
  • changed: constructor Ask(string $question, string|bool|int|float|null $default = …, bool $hidden = …, bool $multiline = …, bool $trimmable = …, ?int $timeout = …, ?callable $normalizer = …, ?callable $validator = …, ?int $maxAttempts = …) → constructor Ask(string $question, string|bool|int|float|null $default = …, bool $hidden = …, bool $multiline = …, bool $trimmable = …, ?int $timeout = …, ?callable $normalizer = …, ?callable $validator = …, ?int $maxAttempts = …, array $constraints = …)
  • added: class AsTargetedValueResolver
  • added: class AskChoice implements InteractiveAttributeInterface
  • added: class MapDateTime
  • added: class ValueResolver
  • added: const Option.ALLOWED_UNION_TYPES
  • added: constructor AsTargetedValueResolver(?string $name = …)
  • added: constructor AskChoice(string $question, array|callable $choices = …, string|int|float|null $default = …, string $errorMessage = …, string $prompt = …, ?callable $validator = …, ?int $maxAttempts = …)
  • added: constructor MapDateTime(?string $format = …, ?string $argument = …, ?string $option = …)
  • added: constructor MapInput(?array $validationGroups = …)
  • added: constructor ValueResolver(string $resolver, bool $disabled = …)
  • added: method AskChoice.getFunction(object $instance): \ReflectionFunction
  • added: method MapInput.createInstance(InputInterface $input): object
  • added: method MapInput.getClass(): \ReflectionClass
  • added: method MapInput.getDefinition(): array
  • added: property Argument.default: mixed
  • added: property Argument.suggestedValues: array|\Closure
  • added: property Argument.typeName: string
  • added: property AsTargetedValueResolver.name: ?string
  • added: property Ask.constraints: array
  • added: property AskChoice.choices: array|\Closure
  • added: property AskChoice.default: string|int|float|null
  • added: property AskChoice.errorMessage: string
  • added: property AskChoice.maxAttempts: ?int
  • added: property AskChoice.prompt: string
  • added: property AskChoice.question: string
  • added: property AskChoice.validator: ?\Closure
  • added: property MapDateTime.argument: ?string
  • added: property MapDateTime.format: ?string
  • added: property MapDateTime.option: ?string
  • added: property MapInput.validationGroups: ?array
  • added: property Option.allowNull: bool
  • added: property Option.default: mixed
  • added: property Option.suggestedValues: array|\Closure
  • added: property Option.typeName: string
  • added: property ValueResolver.disabled: bool
  • added: property ValueResolver.resolver: string
  • added: static method AskChoice.tryFrom(\ReflectionParameter|\ReflectionProperty $member, string $name): ?self
  • added: method ReflectionMember.getAttributes(string $class): array
  • added: method ReflectionMember.getInputName(): string
  • added: method ReflectionMember.getMember(): \ReflectionParameter|\ReflectionProperty
  • added: method ReflectionMember.isVariadic(): bool
  • removed: static method Command.getDefaultDescription(): ?string
  • removed: static method Command.getDefaultName(): ?string
  • changed: constructor InvokableCommand(Command $command, callable $code) → constructor InvokableCommand(Command $command, callable $code, ?ArgumentResolverInterface $argumentResolver = …)
  • changed: protected method Command.configure() → protected method Command.configure(): void
  • changed: protected method Command.initialize(InputInterface $input, OutputInterface $output) → protected method Command.initialize(InputInterface $input, OutputInterface $output): void
  • changed: protected method Command.interact(InputInterface $input, OutputInterface $output) → protected method Command.interact(InputInterface $input, OutputInterface $output): void
  • added: class ConsoleArgumentValueResolverPass implements CompilerPassInterface
  • added: final class RegisterCommandArgumentLocatorsPass implements CompilerPassInterface
  • added: final class RemoveEmptyCommandArgumentLocatorsPass implements CompilerPassInterface
  • added: method ConsoleArgumentValueResolverPass.process(ContainerBuilder $container): void
  • added: method RegisterCommandArgumentLocatorsPass.process(ContainerBuilder $container): void
  • added: method RemoveEmptyCommandArgumentLocatorsPass.process(ContainerBuilder $container): void
  • added: class QuestionAnsweredEvent extends Event
  • added: constructor QuestionAnsweredEvent(mixed $value, array $constraints)
  • added: method QuestionAnsweredEvent.addViolation(string $message): void
  • added: method QuestionAnsweredEvent.getViolations(): array
  • added: method QuestionAnsweredEvent.hasViolations(): bool
  • added: property QuestionAnsweredEvent.constraints: array
  • added: property QuestionAnsweredEvent.value: mixed
  • added: constructor ValidateQuestionInputListener(ValidatorInterface $validator)
  • added: final class ValidateQuestionInputListener implements EventSubscriberInterface
  • added: method ValidateQuestionInputListener.onQuestionAnswered(QuestionAnsweredEvent $event): void
  • added: static method ValidateQuestionInputListener.getSubscribedEvents(): array
  • added: class InvalidFileException extends \RuntimeException implements ExceptionInterface
  • added: constructor InputValidationFailedException(string $message, ConstraintViolationListInterface $violations)
  • added: constructor InvalidFileException(string $message = …, int $code = …, ?\Throwable $previous = …)
  • added: final class InputValidationFailedException extends RuntimeException
  • added: method InputValidationFailedException.getViolations(): ConstraintViolationListInterface
  • changed: method ProgressIndicator.finish(string $message): void → method ProgressIndicator.finish(string $message, ?string $finishedIndicator = …): void
  • added: constructor QuestionHelper(?EventDispatcherInterface $dispatcher = …)
  • added: final class FileInputHelper
  • added: method FileInputHelper.displayFile(OutputInterface $output, InputFile $file): void
  • added: method FileInputHelper.readFileInput($inputStream, OutputInterface $output, FileQuestion $question): InputFile
  • added: static method ProgressBar.pauseAll(): void
  • added: static method ProgressBar.resumeAll(): void
  • changed: abstract class Input implements InputInterface, StreamableInputInterface → abstract class Input implements RawInputInterface, StreamableInputInterface
  • changed: constructor InputArgument(string $name, ?int $mode = …, string $description = …, string|bool|int|float|array|null $default = …, \Closure|array $suggestedValues = …) → constructor InputArgument(string $name, ?int $mode = …, string $description = …, mixed $default = …, \Closure|array $suggestedValues = …)
  • changed: constructor InputOption(string $name, string|array|null $shortcut = …, ?int $mode = …, string $description = …, string|bool|int|float|array|null $default = …, array|\Closure $suggestedValues = …) → constructor InputOption(string $name, string|array|null $shortcut = …, ?int $mode = …, string $description = …, mixed $default = …, array|\Closure $suggestedValues = …)
  • changed: method InputArgument.getDefault(): string|bool|int|float|array|null → method InputArgument.getDefault(): mixed
  • changed: method InputArgument.setDefault(string|bool|int|float|array|null $default): void → method InputArgument.setDefault(mixed $default): void
  • changed: method InputOption.getDefault(): string|bool|int|float|array|null → method InputOption.getDefault(): mixed
  • changed: method InputOption.setDefault(string|bool|int|float|array|null $default): void → method InputOption.setDefault(mixed $default): void
  • added: interface RawInputInterface extends InputInterface
  • added: method Input.getRawArguments(): array
  • added: method Input.getRawOptions(): array
  • added: method Input.unparse(?array $optionNames = …): array
  • added: method RawInputInterface.getRawArguments(): array
  • added: method RawInputInterface.getRawOptions(): array
  • added: method RawInputInterface.unparse(?array $optionNames = …): array
  • added: constructor InputFile(string $path, bool $isTempFile = …, ?string $mimeType = …)
  • added: final class InputFile extends \SplFileInfo
  • added: method InputFile.cleanup(): void
  • added: method InputFile.getContents(): string
  • added: method InputFile.getHumanReadableSize(): string
  • added: method InputFile.getMimeType(): ?string
  • added: method InputFile.guessExtension(): ?string
  • added: method InputFile.isTempFile(): bool
  • added: method InputFile.isValid(): bool
  • added: method InputFile.move(string $directory, ?string $name = …): self
  • added: static method InputFile.cleanupAll(): void
  • added: static method InputFile.fromData(string $data, ?string $format = …): self
  • added: static method InputFile.fromPath(string $path): self
  • added: constructor CombinedOutput(array $outputs)
  • added: constructor TestOutput(bool $decorated, int $verbosity, ?OutputFormatterInterface $formatter = …)
  • added: final class CombinedOutput implements OutputInterface
  • added: final class TestOutput implements ConsoleOutputInterface
  • added: method CombinedOutput.getFormatter(): OutputFormatterInterface
  • added: method CombinedOutput.getVerbosity(): int
  • added: method CombinedOutput.isDebug(): bool
  • added: method CombinedOutput.isDecorated(): bool
  • added: method CombinedOutput.isQuiet(): bool
  • added: method CombinedOutput.isSilent(): bool
  • added: method CombinedOutput.isVerbose(): bool
  • added: method CombinedOutput.isVeryVerbose(): bool
  • added: method CombinedOutput.setDecorated(bool $decorated): void
  • added: method CombinedOutput.setFormatter(OutputFormatterInterface $formatter): void
  • added: method CombinedOutput.setVerbosity(int $level): void
  • added: method CombinedOutput.write(iterable|string $messages, bool $newline = …, int $options = …): void
  • added: method CombinedOutput.writeln(iterable|string $messages, int $options = …): void
  • added: method OutputInterface.isSilent(): bool
  • added: method TestOutput.getDisplayContents(): string
  • added: method TestOutput.getErrorOutput(): OutputInterface
  • added: method TestOutput.getErrorOutputContents(): string
  • added: method TestOutput.getFormatter(): OutputFormatterInterface
  • added: method TestOutput.getOutputContents(): string
  • added: method TestOutput.getVerbosity(): int
  • added: method TestOutput.isDebug(): bool
  • added: method TestOutput.isDecorated(): bool
  • added: method TestOutput.isQuiet(): bool
  • added: method TestOutput.isSilent(): bool
  • added: method TestOutput.isVerbose(): bool
  • added: method TestOutput.isVeryVerbose(): bool
  • added: method TestOutput.section(): ConsoleSectionOutput
  • added: method TestOutput.setDecorated(bool $decorated): void
  • added: method TestOutput.setErrorOutput(OutputInterface $error): void
  • added: method TestOutput.setFormatter(OutputFormatterInterface $formatter): void
  • added: method TestOutput.setVerbosity(int $level): void
  • added: method TestOutput.write(iterable|string $messages, bool $newline = …, int $options = …): void
  • added: method TestOutput.writeln(iterable|string $messages, int $options = …): void
  • added: class FileQuestion extends Question
  • added: constructor FileQuestion(string $question, bool $allowPaste = …, bool $allowPath = …)
  • added: method FileQuestion.isPasteAllowed(): bool
  • added: method FileQuestion.isPathAllowed(): bool
  • added: method Question.getConstraints(): array
  • added: method Question.setConstraints(array $constraints): static
  • changed: constructor SymfonyStyle(InputInterface $input, OutputInterface $output) → constructor SymfonyStyle(InputInterface $input, OutputInterface $output, ?EventDispatcherInterface $dispatcher = …)
  • added: method SymfonyStyle.askFile(string $question): ?InputFile
  • added: method SymfonyStyle.outlineBlock(string|array $messages, ?string $type = …, ?string $style = …, bool $padding = …, bool $escape = …): void
  • added: method SymfonyStyle.outlineCaution(string|array $message): void
  • added: method SymfonyStyle.outlineError(string|array $message): void
  • added: method SymfonyStyle.outlineInfo(string|array $message): void
  • added: method SymfonyStyle.outlineNote(string|array $message): void
  • added: method SymfonyStyle.outlineSuccess(string|array $message): void
  • added: method SymfonyStyle.outlineWarning(string|array $message): void
  • added: const ITerm2Protocol.BEL
  • added: const ITerm2Protocol.OSC_START
  • added: const ITerm2Protocol.ST
  • added: const KittyGraphicsProtocol.APC_START
  • added: const KittyGraphicsProtocol.ST
  • added: final class ITerm2Protocol implements ImageProtocolInterface
  • added: final class KittyGraphicsProtocol implements ImageProtocolInterface
  • added: interface ImageProtocolInterface
  • added: method ITerm2Protocol.decode(string $data): array
  • added: method ITerm2Protocol.detectPastedImage(string $data): bool
  • added: method ITerm2Protocol.encode(string $imageData, ?int $maxWidth = …): string
  • added: method ITerm2Protocol.getName(): string
  • added: method ImageProtocolInterface.decode(string $data): array
  • added: method ImageProtocolInterface.detectPastedImage(string $data): bool
  • added: method ImageProtocolInterface.encode(string $imageData, ?int $maxWidth = …): string
  • added: method ImageProtocolInterface.getName(): string
  • added: method KittyGraphicsProtocol.decode(string $data): array
  • added: method KittyGraphicsProtocol.detectPastedImage(string $data): bool
  • added: method KittyGraphicsProtocol.encode(string $imageData, ?int $maxWidth = …): string
  • added: method KittyGraphicsProtocol.getName(): string
  • changed: constructor CommandTester(callable|Command $command) → constructor CommandTester(callable|Command $command, ?bool $interactive = …, bool $decorated = …, int $verbosity = …, ?OutputFormatterInterface $outputFormatter = …)
  • added: constructor ExecutionResult(string $input, int $statusCode, TestOutput $output, array $normalizers = …)
  • added: final class ExecutionResult
  • added: method CommandTester.run(array $input = …, array $interactiveInputs = …, ?bool $interactive = …, ?bool $decorated = …, ?int $verbosity = …, array $normalizers = …): ExecutionResult
  • added: method CommandTester.setDecorated(bool $decorated): void
  • added: method CommandTester.setInteractive(bool $interactive): void
  • added: method CommandTester.setOutputFormatter(OutputFormatterInterface $outputFormatter): void
  • added: method CommandTester.setVerbosity(int $level): void
  • added: method ConsoleAssertionsTrait.assertCommandFailed(ExecutionResult $result, string $message = …): void
  • added: method ConsoleAssertionsTrait.assertCommandIsInvalid(ExecutionResult $result, string $message = …): void
  • added: method ConsoleAssertionsTrait.assertCommandIsSuccessful(ExecutionResult $result, string $message = …): void
  • added: method ConsoleAssertionsTrait.assertCommandResultEquals(ExecutionResult $result, ?int $expectedStatusCode = …, ?string $expectedOutput = …, ?string $expectedErrorOutput = …, ?string $expectedDisplay = …, string $message = …): void
  • added: method ExecutionResult.dd(): never
  • added: method ExecutionResult.dump(): static
  • added: method ExecutionResult.getDisplay(bool $normalize = …): string
  • added: method ExecutionResult.getErrorOutput(bool $normalize = …): string
  • added: method ExecutionResult.getOutput(bool $normalize = …): string
  • added: method TesterTrait.assertCommandFailed(string $message = …): void
  • added: method TesterTrait.assertCommandIsInvalid(string $message = …): void
  • added: property ExecutionResult.input: string
  • added: property ExecutionResult.statusCode: int
  • added: trait ConsoleAssertionsTrait
  • added: final class CommandFailed extends Constraint
  • added: final class CommandIsInvalid extends Constraint
  • added: method CommandFailed.toString(): string
  • added: method CommandIsInvalid.toString(): string
  • added: protected method CommandFailed.additionalFailureDescription($other): string
  • added: protected method CommandFailed.failureDescription($other): string
  • added: protected method CommandFailed.matches($other): bool
  • added: protected method CommandIsInvalid.additionalFailureDescription($other): string
  • added: protected method CommandIsInvalid.failureDescription($other): string
  • added: protected method CommandIsInvalid.matches($other): bool