CodeSampleX

Пример

symfony/console 8.1.4: Preserve input types and values across Symfony Console ArrayInput string serialization, StringInput single-quote escape handling, and ArgvInput re-binding

Проверенный пример — composer symfony/console 8.1.4: Preserve input types and values across Symfony Console ArrayInput string serialization, StringInput…

sha256:4aff81928d83c14745510bd1f4d6811c8ea779881c9bce8e5dc69ad8cc10cb7c

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
2
Ключи подписи, собравшие его
2
Заявленная среда php linux x64 php php composer

Среды запусков проверки

Окружение Контракт Этапы Запуск
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

Кейс

HOW
Цель
Preserve input types and values across Symfony Console ArrayInput string serialization, StringInput single-quote escape handling, and ArgvInput re-binding
Пакеты
Символы
  • Symfony\Component\Console\Input\ArrayInput
  • Symfony\Component\Console\Input\StringInput
  • Symfony\Component\Console\Input\InputOption
Окружение
php
Создан
2026-08-16T14:02:07Z

Контракт

  1. ArrayInput::__toString() serializes a boolean true flag as '--flag=1', which throws RuntimeException when rebound to a VALUE_NONE option, and serializes a boolean false flag as '--flag', which inverts the flag to true when reparsed.
  2. ArrayInput::__toString() serializes a false VALUE_NEGATABLE option as '--flag' rather than '--no-flag', inverting the negatable option to true upon StringInput rebinding.
  3. ArrayInput::__toString() wraps hyphen-prefixed positional arguments in quotes without escaping the leading dash, causing StringInput to parse them as unrecognized short options.
  4. ArrayInput::__toString() strips the assignment operator from empty-string option values, causing StringInput to reparse VALUE_OPTIONAL options as null rather than an empty string.
  5. StringInput applies stripcslashes to single-quoted strings identically to double-quoted strings, transforming escaped control characters like backslash-t and backslash-n into raw tab and newline bytes rather than literal characters.
  6. ArrayInput preserves native PHP integer, float, and boolean types across getArgument() and getOption(), whereas StringInput coerces all non-flag arguments and options into raw strings.

Файлы

  • NOTES.md
  • composer.json
  • composer.lock
  • csx.json
  • test/contract.php

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

NOTES.md
# Notes on symfony/console Type and Serialization Boundaries

### What `search_known_solution` answered
`search_known_solution` returned three existing samples:
- `sha256:64ffbaaec11e20300f534cf6b8b955bf63ed41b80dd1cf1bcba3f0df84e46ff7` covering `InputOption` default validation and `Application::addCommand` vs `add`
- `sha256:920790665b5eccaf71a293546cc111191874497b72b8fb0832384c5548a61e45` covering error path exception types across `ArgvInput` and `ArrayInput`
- `sha256:b51af65d0a29d58f2da432207c6472d366b11c2d5b6782709161c5e318fad7d2` covering silent verbosity and greedy token capture

None of the existing samples cover `ArrayInput` stringification round-trip mutations, `StringInput` single-quote escape interpretation, or cross-input type retention versus CLI string parsing.

### What a model would have written instead
A competent model chaining console commands, logging CLI executions, or constructing sub-processes with `(string) $arrayInput` expects the stringified output to faithfully represent the command and round-trip cleanly through `StringInput`. It expects `VALUE_NONE` flags to serialize as `--flag` (or omit when `false`), `VALUE_NEGATABLE` flags to serialize as `--no-flag` when `false`, single-quoted inputs in `StringInput` to preserve literal backslashes without expanding C escape sequences, and `getArgument()` / `getOption()` to return identical types across `ArrayInput` and `StringInput`.

### How the wrong version fails
- **`ArrayInput` true `VALUE_NONE` flag round-trip**: Fails loudly with `Symfony\Component\Console\Exception\RuntimeException: The "--dry-run" option does not accept a value.` because `ArrayInput::__toString()` appends `=1` to boolean flags.
- **`ArrayInput` false flag round-trip**: Fails silently with a green build but inverted application state because `ArrayInput(['--dry-run' => false])` emits `--dry-run`, which `StringInput` binds as `true`.
- **`ArrayInput` false `VALUE_NEGATABLE` option**: Fails silently with a green build and inverted state because `ArrayInput(['--ansi' => false])` emits `--ansi` instead of `--no-ansi`, resolving to `true` on reparsing.
- **Hyphen-prefixed argument round-trip**: Fails loudly with `Symfony\Component\Console\Exception\RuntimeException: The "-d" option does not exist.` because quotes are stripped during tokenization, exposing the leading dash to short option parsing.
- **Empty-string option value round-trip**: Fails silently with incorrect downstream data because `ArrayInput(['--prefix' => ''])` emits `--prefix` without `=`, causing `VALUE_OPTIONAL` options to resolve to `null` instead of `""`.
- **Single-quoted string escape sequence parsing**: Fails silently with corrupted string data because `StringInput` applies `stripcslashes()` to both single and double quotes, turning `\t` and `\n` into ASCII `0x09` and `0x0A` bytes.
- **Type boundary across input implementations**: Fails loudly at runtime under strict types with `TypeError: Argument must be of type int, string given` when transitioning from test environments using `ArrayInput` (which retains native `int` types) to CLI execution using `StringInput` or `ArgvInput` (which always returns `string`).
composer.json
{
    "require": {
        "symfony/console": "^8.1"
    }
}
composer.lock
{
    "_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": "25343571212bf782a5ebe4b930411fec",
    "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"
}
csx.json
{"case":{"believed":"Serializing an ArrayInput instance to a CLI string with __toString() produces argument tokens that preserve boolean flag states and option values when round-tripped through StringInput.","caseId":"case:sha256:77861dc496898d738e8fbbb38c97080c6e9a048736ce90401e3feb644c7cd493","contract":["ArrayInput::__toString() serializes a boolean true flag as '--flag=1', which throws RuntimeException when rebound to a VALUE_NONE option, and serializes a boolean false flag as '--flag', which inverts the flag to true when reparsed.","ArrayInput::__toString() serializes a false VALUE_NEGATABLE option as '--flag' rather than '--no-flag', inverting the negatable option to true upon StringInput rebinding.","ArrayInput::__toString() wraps hyphen-prefixed positional arguments in quotes without escaping the leading dash, causing StringInput to parse them as unrecognized short options.","ArrayInput::__toString() strips the assignment operator from empty-string option values, causing StringInput to reparse VALUE_OPTIONAL options as null rather than an empty string.","StringInput applies stripcslashes to single-quoted strings identically to double-quoted strings, transforming escaped control characters like backslash-t and backslash-n into raw tab and newline bytes rather than literal characters.","ArrayInput preserves native PHP integer, float, and boolean types across getArgument() and getOption(), whereas StringInput coerces all non-flag arguments and options into raw strings."],"goal":"Preserve input types and values across Symfony Console ArrayInput string serialization, StringInput single-quote escape handling, and ArgvInput re-binding","kind":"HOW","packages":["pkg:composer/symfony/console@8.1.4"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Input\\ArrayInput","Symfony\\Component\\Console\\Input\\StringInput","Symfony\\Component\\Console\\Input\\InputOption"]},"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\\ArrayInput","Symfony\\Component\\Console\\Input\\StringInput","Symfony\\Component\\Console\\Input\\InputOption"],"verifierAdapter":"composer@1"}
test/contract.php
<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\Console\Exception\RuntimeException;
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\Input\StringInput;

// 1. ArrayInput::__toString() serializes a boolean true flag as '--flag=1', which throws
//    RuntimeException when rebound to a VALUE_NONE option, and serializes a boolean false flag
//    as '--flag', which inverts the flag to true when reparsed.
$defFlag = new InputDefinition([
    new InputOption('dry-run', null, InputOption::VALUE_NONE),
]);

$arrTrue = new ArrayInput(['--dry-run' => true]);
assert((string)$arrTrue === '--dry-run=1', 'true VALUE_NONE flag stringifies as --dry-run=1');

$caughtTrueException = false;
try {
    $strFromTrue = new StringInput((string)$arrTrue);
    $strFromTrue->bind($defFlag);
} catch (RuntimeException $e) {
    $caughtTrueException = true;
    assert($e->getMessage() === 'The "--dry-run" option does not accept a value.');
}
assert($caughtTrueException, 'Binding --dry-run=1 to VALUE_NONE must throw RuntimeException');

$arrFalse = new ArrayInput(['--dry-run' => false]);
assert((string)$arrFalse === '--dry-run', 'false VALUE_NONE flag stringifies as --dry-run rather than being omitted');

$strFromFalse = new StringInput((string)$arrFalse);
$strFromFalse->bind($defFlag);
assert($strFromFalse->getOption('dry-run') === true, 'Reparsing stringified false flag inverts value to true');


// 2. ArrayInput::__toString() serializes a false VALUE_NEGATABLE option as '--flag' rather than
//    '--no-flag', inverting the negatable option to true upon StringInput rebinding.
$defNeg = new InputDefinition([
    new InputOption('ansi', null, InputOption::VALUE_NEGATABLE),
]);

$arrNegFalse = new ArrayInput(['--ansi' => false]);
assert((string)$arrNegFalse === '--ansi', 'false VALUE_NEGATABLE stringifies as --ansi instead of --no-ansi');

$strNeg = new StringInput((string)$arrNegFalse);
$strNeg->bind($defNeg);
assert($strNeg->getOption('ansi') === true, 'Reparsing stringified negatable false flag inverts value to true');


// 3. ArrayInput::__toString() wraps hyphen-prefixed positional arguments in quotes without
//    escaping the leading dash, causing StringInput to parse them as unrecognized short options.
$defArg = new InputDefinition([
    new InputArgument('filename', InputArgument::REQUIRED),
]);

$arrArgDash = new ArrayInput(['filename' => '-data.txt']);
assert(str_contains((string)$arrArgDash, '-data.txt'), 'Stringified argument retains leading dash');

$caughtDashException = false;
try {
    $strArg = new StringInput((string)$arrArgDash);
    $strArg->bind($defArg);
} catch (RuntimeException $e) {
    $caughtDashException = true;
    assert($e->getMessage() === 'The "-d" option does not exist.');
}
assert($caughtDashException, 'Reparsing hyphen-prefixed argument causes parser to treat it as short option -d');


// 4. ArrayInput::__toString() strips the assignment operator from empty-string option values,
//    causing StringInput to reparse VALUE_OPTIONAL options as null rather than an empty string.
$defOpt = new InputDefinition([
    new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, '', 'default_prefix'),
]);

$arrEmptyOpt = new ArrayInput(['--prefix' => '']);
assert((string)$arrEmptyOpt === '--prefix', 'Empty string option value stringifies without = value');

$strOpt = new StringInput((string)$arrEmptyOpt);
$strOpt->bind($defOpt);
assert($strOpt->getOption('prefix') === null, 'Reparsing --prefix without = yields null instead of empty string');


// 5. StringInput applies stripcslashes to single-quoted strings identically to double-quoted
//    strings, transforming escaped control characters like backslash-t and backslash-n into
//    raw tab and newline bytes rather than literal characters.
$defPath = new InputDefinition([
    new InputArgument('path', InputArgument::REQUIRED),
]);

$rawSingleQuoted = "'data\\temp\\notes.txt'";
$strSingle = new StringInput($rawSingleQuoted);
$strSingle->bind($defPath);
$parsedPath = $strSingle->getArgument('path');

assert($parsedPath === "data\temp\notes.txt", 'Single-quoted input undergoes stripcslashes conversion');
assert(str_contains($parsedPath, "\t"), 'Parsed single-quoted string contains raw ASCII tab byte 0x09');
assert(str_contains($parsedPath, "\n"), 'Parsed single-quoted string contains raw ASCII newline byte 0x0A');
assert($parsedPath !== 'data\temp\notes.txt', 'Parsed single-quoted string loses literal backslash sequences');


// 6. ArrayInput preserves native PHP integer, float, and boolean types across getArgument() and
//    getOption(), whereas StringInput coerces all non-flag arguments and options into raw strings.
$defTypes = new InputDefinition([
    new InputArgument('count', InputArgument::REQUIRED),
    new InputOption('ratio', null, InputOption::VALUE_REQUIRED),
]);

$arrTyped = new ArrayInput(['count' => 100, '--ratio' => 2.5], $defTypes);
assert(is_int($arrTyped->getArgument('count')) && $arrTyped->getArgument('count') === 100);
assert(is_float($arrTyped->getOption('ratio')) && $arrTyped->getOption('ratio') === 2.5);

$strTyped = new StringInput('100 --ratio=2.5');
$strTyped->bind($defTypes);
assert(is_string($strTyped->getArgument('count')) && $strTyped->getArgument('count') === '100');
assert(is_string($strTyped->getOption('ratio')) && $strTyped->getOption('ratio') === '2.5');

echo "All symfony/console serialization and type boundary contract checks passed successfully.\n";

Исходный сидер

csx-seed