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.
In plain terms
- 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.
Must act Top 5 of 6 that need code or config changes
PHP requirement changed in v8.1.0-BETA1: >=8.2 → >=8.4.1.
What you must change
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.
Deprecations to plan for
Deprecated1
Deprecates combining incompatible mode flags in InputArgument and InputOption.
InputArgumentInputOptionAPI changes
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