Beispiel
symfony/console 8.1.4: Handle Symfony Console input error path exception types and exit codes across ArgvInput and ArrayInput
Verifiziertes Beispiel für composer symfony/console 8.1.4: Handle Symfony Console input error path exception types and exit codes across ArgvInput and…
sha256:920790665b5eccaf71a293546cc111191874497b72b8fb0832384c5548a61e45
Dieses Netzwerk bietet eine Sache: ein Sample, das baut. Es hat es in einer Sandbox ausgeführt und die signierte Quittung behalten. Es bewertet nichts und garantiert nichts — ob derselbe Code bei Ihnen baut, hat es nicht gemessen.
Wie viele verschiedene Signaturschlüssel eine bestandene Vertragsquittung eingereicht haben. Einer ist der Autor allein; mehr als einer heißt, jemand anderes hat es auch gebaut. Ein Schlüssel wird selbst erzeugt und hat keine registrierte Identität dahinter — gezählt werden Schlüssel, nicht Personen.
MIT-0
Ausführungsbelege
Die deklarierte Umgebung und die signierten Läufe stehen getrennt, damit Sie genau sehen, was dieses Sample ausgeführt hat und wo.
- Beleggrundlage
- Signierter Vertrag bestanden
- Verifizierungsbelege
- 2
- Signaturschlüssel, die es gebaut haben
- 2
Deklarierte Umgebung
php linux x64 php php composer
Umgebungen der Verifizierungsläufe
| Umgebung | Contract | Stufen | Lauf |
|---|---|---|---|
| php 8 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · composer@1 |
2026-08-16 |
| php 8 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · composer@1 |
2026-08-18 |
Fall
HOW- Ziel
- Handle Symfony Console input error path exception types and exit codes across ArgvInput and ArrayInput
- Pakete
- Symbole
-
- Symfony\Component\Console\Input\ArgvInput
- Symfony\Component\Console\Input\ArrayInput
- Symfony\Component\Console\Exception\RuntimeException
- Symfony\Component\Console\Exception\InvalidOptionException
- Symfony\Component\Console\Exception\MissingInputException
- Symfony\Component\Console\Application
- Umgebung
- php
- Erstellt
- 2026-08-16T12:40:37Z
Contract
- ArgvInput with an unknown option throws RuntimeException rather than InvalidOptionException or InvalidArgumentException
- Missing required arguments throw RuntimeException rather than MissingInputException
- ArgvInput with missing VALUE_REQUIRED option value throws RuntimeException rather than InvalidOptionException
- ArrayInput throws InvalidOptionException for unknown options, creating an exception type divergence from ArgvInput
- Application::run() on input validation failure returns Command::FAILURE (1) instead of Command::INVALID (2)
- ArrayInput preserves raw scalar strings for VALUE_IS_ARRAY options instead of boxing them into an array
Dateien
- NOTES.md
- composer.json
- composer.lock
- csx.json
- test/contract.php
Quelltext
# Notes on symfony/console Input Error Paths and Exception Types
## What search_known_solution answered
`search_known_solution` returned existing samples `sha256:b51af65d0a29d58f2da432207c6472d366b11c2d5b6782709161c5e318fad7d2` (covering silent verbosity suppressing exception rendering, `VALUE_NEGATABLE` defaults, `ArgvInput` optional token capture, and `ChoiceQuestion` return types) and `sha256:64ffbaaec11e20300f534cf6b8b955bf63ed41b80dd1cf1bcba3f0df84e46ff7` (covering `InputOption::VALUE_NONE` default validation and `Application::addCommand`). This sample addresses a different trap: input error handling paths, exception type divergences between `ArgvInput` and `ArrayInput`, `MissingInputException` vs `RuntimeException`, `Application::run()` exit code defaults on invalid input, and scalar preservation on array options.
## What a model would write instead
A model handling CLI input errors writes `catch (InvalidOptionException $e)` or `catch (InvalidArgumentException $e)` around `$input->bind()` to intercept invalid command-line flags, expects omitted positional arguments to throw `MissingInputException`, assumes `Application::run()` returns `Command::INVALID` (exit code 2) on command syntax and validation failures, and supplies scalar strings to `ArrayInput` assuming automatic array wrapping for `VALUE_IS_ARRAY` options.
## How the wrong version fails
It fails loudly when exception handlers for `InvalidOptionException`, `InvalidArgumentException`, or `MissingInputException` let unhandled `RuntimeException` instances crash the process, and fails silently with a green build when tests checking `Application::run() === Command::INVALID` evaluate to false because `1` (`Command::FAILURE`) was returned, or when `ArrayInput` leaves scalar values unboxed as raw strings on `VALUE_IS_ARRAY` options.
{
"require": {
"symfony/console": "^8.1"
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ad6bc9bbba6295a61d977bca4a0654b9",
"packages": [
{
"name": "psr/container",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/container.git",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
"shasum": ""
},
"require": {
"php": ">=7.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Container\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common Container Interface (PHP FIG PSR-11)",
"homepage": "https://github.com/php-fig/container",
"keywords": [
"PSR-11",
"container",
"container-interface",
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/2.0.2"
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "symfony/console",
"version": "v8.1.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "68efa2ebfd9a362951eb5a8b09fd177c66ddec24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/68efa2ebfd9a362951eb5a8b09fd177c66ddec24",
"reference": "68efa2ebfd9a362951eb5a8b09fd177c66ddec24",
"shasum": ""
},
"require": {
"php": ">=8.4.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-mbstring": "^1.0",
"symfony/polyfill-php85": "^1.32",
"symfony/service-contracts": "^2.5|^3",
"symfony/string": "^7.4.6|^8.0.6"
},
"conflict": {
"symfony/dependency-injection": "<8.1",
"symfony/event-dispatcher": "<8.1"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^7.4|^8.0",
"symfony/dependency-injection": "^8.1",
"symfony/event-dispatcher": "^8.1",
"symfony/filesystem": "^7.4|^8.0",
"symfony/http-foundation": "^7.4|^8.0",
"symfony/http-kernel": "^7.4|^8.0",
"symfony/lock": "^7.4|^8.0",
"symfony/messenger": "^7.4|^8.0",
"symfony/mime": "^7.4|^8.0",
"symfony/process": "^7.4|^8.0",
"symfony/stopwatch": "^7.4|^8.0",
"symfony/uid": "^7.4|^8.0",
"symfony/validator": "^7.4|^8.0",
"symfony/var-dumper": "^7.4|^8.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Eases the creation of beautiful and testable command line interfaces",
"homepage": "https://symfony.com",
"keywords": [
"cli",
"command-line",
"console",
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v8.1.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-07-31T12:43:13+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.7.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d",
"reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.7-dev"
}
},
"autoload": {
"files": [
"function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-06-05T06:23:12+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.37.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "141046a8f9477948ff284fa65be2095baafb94f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
"reference": "141046a8f9477948ff284fa65be2095baafb94f2",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-04-10T16:19:22+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.41.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
"reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Grapheme\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's grapheme_* functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"grapheme",
"intl",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-07-28T08:25:59+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.38.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Intl\\Normalizer\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for intl's Normalizer class and related functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"intl",
"normalizer",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-05-25T13:48:31+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.38.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
"reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-05-27T06:59:30+00:00"
},
{
"name": "symfony/polyfill-php85",
"version": "v1.41.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php85.git",
"reference": "255fab485aaa1006ed411040c42aecd7b5302d7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/255fab485aaa1006ed411040c42aecd7b5302d7a",
"reference": "255fab485aaa1006ed411040c42aecd7b5302d7a",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php85\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php85/tree/v1.41.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-07-01T12:47:55+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.7.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0",
"reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.7-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Service\\": ""
},
"exclude-from-classmap": [
"/Test/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to writing services",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.7.1"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-06-16T09:55:08+00:00"
},
{
"name": "symfony/string",
"version": "v8.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc",
"reference": "286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc",
"shasum": ""
},
"require": {
"php": ">=8.4.1",
"symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-intl-grapheme": "^1.33",
"symfony/polyfill-intl-normalizer": "^1.0",
"symfony/polyfill-mbstring": "^1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
"symfony/emoji": "^7.4|^8.0",
"symfony/http-client": "^7.4|^8.0",
"symfony/intl": "^7.4|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
"symfony/var-exporter": "^7.4|^8.0"
},
"type": "library",
"autoload": {
"files": [
"Resources/functions.php"
],
"psr-4": {
"Symfony\\Component\\String\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
"homepage": "https://symfony.com",
"keywords": [
"grapheme",
"i18n",
"string",
"unicode",
"utf-8",
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v8.1.2"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-07-28T07:35:25+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.9.0"
}
{"case":{"believed":"Unrecognized CLI options throw InvalidOptionException and missing required arguments throw MissingInputException.","caseId":"case:sha256:a017f769a2c8db94cd9c29c4904afb6dec62e93ae5e523cdd1c8a8c1e46dbe21","contract":["ArgvInput with an unknown option throws RuntimeException rather than InvalidOptionException or InvalidArgumentException","Missing required arguments throw RuntimeException rather than MissingInputException","ArgvInput with missing VALUE_REQUIRED option value throws RuntimeException rather than InvalidOptionException","ArrayInput throws InvalidOptionException for unknown options, creating an exception type divergence from ArgvInput","Application::run() on input validation failure returns Command::FAILURE (1) instead of Command::INVALID (2)","ArrayInput preserves raw scalar strings for VALUE_IS_ARRAY options instead of boxing them into an array"],"goal":"Handle Symfony Console input error path exception types and exit codes across ArgvInput and ArrayInput","kind":"HOW","packages":["pkg:composer/symfony/console@8.1.4"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Input\\ArgvInput","Symfony\\Component\\Console\\Input\\ArrayInput","Symfony\\Component\\Console\\Exception\\RuntimeException","Symfony\\Component\\Console\\Exception\\InvalidOptionException","Symfony\\Component\\Console\\Exception\\MissingInputException","Symfony\\Component\\Console\\Application"]},"contractCommand":["php","test/contract.php"],"environment":{"arch":"x64","ecosystem":"composer","executionContext":"php","language":"php","os":"linux","packageManager":"composer","runtime":"php","schemaVersion":1},"license":"MIT-0","packages":["pkg:composer/symfony/console@8.1.4"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Input\\ArgvInput","Symfony\\Component\\Console\\Input\\ArrayInput","Symfony\\Component\\Console\\Exception\\RuntimeException","Symfony\\Component\\Console\\Exception\\InvalidOptionException","Symfony\\Component\\Console\\Exception\\MissingInputException","Symfony\\Component\\Console\\Application"],"verifierAdapter":"composer@1"}
<?php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\InvalidOptionException;
use Symfony\Component\Console\Exception\MissingInputException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\BufferedOutput;
function assertCondition(bool $condition, string $message): void
{
if (!$condition) {
throw new \AssertionError("Contract failed: " . $message);
}
}
// -----------------------------------------------------------------------------
// Trap 1: ArgvInput with unknown option throws RuntimeException, NOT InvalidOptionException or InvalidArgumentException
// -----------------------------------------------------------------------------
$def = new InputDefinition([
new InputOption('verbose-mode', null, InputOption::VALUE_NONE),
new InputArgument('environment', InputArgument::REQUIRED),
]);
$argvWithUnknown = new ArgvInput(['console', '--unknown-opt', 'production']);
$caughtAsInvalidOption = false;
$caughtAsInvalidArgument = false;
$caughtAsRuntime = false;
try {
$argvWithUnknown->bind($def);
} catch (InvalidOptionException $e) {
$caughtAsInvalidOption = true;
} catch (InvalidArgumentException $e) {
$caughtAsInvalidArgument = true;
} catch (RuntimeException $e) {
$caughtAsRuntime = true;
}
assertCondition(!$caughtAsInvalidOption, 'ArgvInput unknown option must NOT be caught by InvalidOptionException');
assertCondition(!$caughtAsInvalidArgument, 'ArgvInput unknown option must NOT be caught by InvalidArgumentException');
assertCondition($caughtAsRuntime, 'ArgvInput unknown option throws RuntimeException instead of InvalidOptionException');
// -----------------------------------------------------------------------------
// Trap 2: Missing required arguments throw RuntimeException, NOT MissingInputException
// -----------------------------------------------------------------------------
$argvMissingArg = new ArgvInput(['console']);
$argvMissingArg->bind($def);
$caughtAsMissingInput = false;
$caughtAsMissingRuntime = false;
try {
$argvMissingArg->validate();
} catch (MissingInputException $e) {
$caughtAsMissingInput = true;
} catch (RuntimeException $e) {
$caughtAsMissingRuntime = true;
}
assertCondition(!$caughtAsMissingInput, 'Missing required argument must NOT throw MissingInputException');
assertCondition($caughtAsMissingRuntime, 'Missing required argument throws RuntimeException');
// -----------------------------------------------------------------------------
// Trap 3: ArgvInput missing VALUE_REQUIRED option value throws RuntimeException, NOT InvalidOptionException
// -----------------------------------------------------------------------------
$defWithReqOpt = new InputDefinition([
new InputOption('config-file', 'c', InputOption::VALUE_REQUIRED),
]);
$argvMissingOptVal = new ArgvInput(['console', '--config-file']);
$optValCaughtAsInvalidOption = false;
$optValCaughtAsRuntime = false;
try {
$argvMissingOptVal->bind($defWithReqOpt);
} catch (InvalidOptionException $e) {
$optValCaughtAsInvalidOption = true;
} catch (RuntimeException $e) {
$optValCaughtAsRuntime = true;
}
assertCondition(!$optValCaughtAsInvalidOption, 'ArgvInput missing option value must NOT throw InvalidOptionException');
assertCondition($optValCaughtAsRuntime, 'ArgvInput missing option value throws RuntimeException');
// -----------------------------------------------------------------------------
// Trap 4: ArrayInput throws InvalidOptionException (and InvalidArgumentException), diverging from ArgvInput
// -----------------------------------------------------------------------------
$arrayInputUnknown = new ArrayInput(['--unknown-opt' => true, 'environment' => 'production']);
$arrayCaughtAsInvalidOption = false;
$arrayCaughtAsRuntime = false;
try {
$arrayInputUnknown->bind($def);
} catch (InvalidOptionException $e) {
$arrayCaughtAsInvalidOption = true;
} catch (RuntimeException $e) {
$arrayCaughtAsRuntime = true;
}
assertCondition($arrayCaughtAsInvalidOption, 'ArrayInput unknown option throws InvalidOptionException');
assertCondition(!$arrayCaughtAsRuntime, 'ArrayInput unknown option does NOT throw RuntimeException (diverging from ArgvInput)');
// -----------------------------------------------------------------------------
// Trap 5: Application::run() returns Command::FAILURE (1), NOT Command::INVALID (2) on input syntax/validation errors
// -----------------------------------------------------------------------------
$app = new Application();
$app->setAutoExit(false);
$cmd = new Command('deploy');
$cmd->addArgument('environment', InputArgument::REQUIRED);
$cmd->setCode(fn() => Command::SUCCESS);
$app->addCommand($cmd);
$outputBuffer = new BufferedOutput();
$exitCode = $app->run(new ArgvInput(['console', 'deploy']), $outputBuffer);
assertCondition($exitCode === Command::FAILURE, 'Application::run() on input failure returns Command::FAILURE (1)');
assertCondition($exitCode !== Command::INVALID, 'Application::run() does NOT return Command::INVALID (2)');
// -----------------------------------------------------------------------------
// Trap 6: ArrayInput with scalar value on VALUE_IS_ARRAY option returns raw string, NOT array
// -----------------------------------------------------------------------------
$defArrayOpt = new InputDefinition([
new InputOption('tags', 't', InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED),
]);
$arrayInputScalar = new ArrayInput(['--tags' => 'single-tag']);
$arrayInputScalar->bind($defArrayOpt);
$tagsValue = $arrayInputScalar->getOption('tags');
assertCondition(is_string($tagsValue), 'ArrayInput scalar value for VALUE_IS_ARRAY remains string');
assertCondition(!is_array($tagsValue), 'ArrayInput does not auto-wrap scalar to array for VALUE_IS_ARRAY options');
echo "All symfony/console error path contract assertions passed successfully.\n";