CodeSampleX

サンプル

symfony/console v8.1.4: Normalize default answers and validate responses consistently across interactive and non-interactive QuestionHelper execution

検証済みサンプル — composer symfony/console v8.1.4: Normalize default answers and validate responses consistently across interactive and non-interactive…

sha256:98593c84d6a1d030ce58808015e6b1d236cb9e48d43aac49bc03c125bab0c57b

このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。 合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。 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
ゴール
Normalize default answers and validate responses consistently across interactive and non-interactive QuestionHelper execution
パッケージ
シンボル
  • Symfony\Component\Console\Helper\QuestionHelper
  • Symfony\Component\Console\Helper\QuestionHelper::ask
  • Symfony\Component\Console\Question\Question
  • Symfony\Component\Console\Question\Question::setNormalizer
  • Symfony\Component\Console\Question\Question::setValidator
環境
php
作成日
2026-08-16T14:41:09Z

コントラクト

  1. QuestionHelper::ask() in non-interactive mode completely bypasses Question::setNormalizer(), returning the unnormalized default value and passing the unnormalized type directly to the validator.
  2. In interactive mode accepting the default value executes Question::setNormalizer() before passing the result to Question::setValidator()
  3. Non-interactive QuestionHelper execution passes the raw unnormalized default to validators, throwing when validators enforce types produced by normalizers
  4. Questions without validators return the normalized string in interactive mode but return the raw unnormalized string in non-interactive mode

ファイル

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

ソースアーティファクトをダウンロード (tar.gz)

ソース

NOTES.md
# Notes

## Network Search Result
A previous sample was found in the network for `symfony/console`: `sha256:89afc201c4bfa004148a13da413c0cb0fe77d5d9ca4e6b45a5bec301d7080e69` (Goal: Accurately calculate Table column widths and wrapping when combining TableCell colspan with per-column setColumnMaxWidth constraints). This sample covers a completely different feature interaction between `Question::setNormalizer()`, `Question::setValidator()`, and non-interactive execution in `QuestionHelper`.

## What a Model Would Have Written Instead
A model assumes that configuring `Question::setNormalizer()` normalizes the question's default value consistently whenever the default is used, both when accepting the default in interactive mode (pressing Enter) and when running non-interactively (`--no-interaction` or `$input->setInteractive(false)`).

## How the Wrong Version Fails
Code relying on normalizers fails loudly with a `RuntimeException` or `TypeError` in non-interactive CI environments when validators expect normalized types (such as integers or parsed arrays), or fails silently with a green build returning raw untrimmed/unnormalized string values to downstream business logic.
composer.json
{
    "require": {
        "symfony/console": "8.1.4"
    }
}
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": "f5b9dc8181c75e9e89cb7b202937cedd",
    "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":"QuestionHelper applies configured Question normalizers to default values in non-interactive execution before validating and returning the response.","caseId":"case:sha256:c01cf599507af5f6610a41d1106ce46ac642ce8f7e97350b51ac0d80e4970cad","contract":["QuestionHelper::ask() in non-interactive mode completely bypasses Question::setNormalizer(), returning the unnormalized default value and passing the unnormalized type directly to the validator.","In interactive mode accepting the default value executes Question::setNormalizer() before passing the result to Question::setValidator()","Non-interactive QuestionHelper execution passes the raw unnormalized default to validators, throwing when validators enforce types produced by normalizers","Questions without validators return the normalized string in interactive mode but return the raw unnormalized string in non-interactive mode"],"goal":"Normalize default answers and validate responses consistently across interactive and non-interactive QuestionHelper execution","kind":"HOW","packages":["pkg:composer/symfony/console@v8.1.4"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Helper\\QuestionHelper","Symfony\\Component\\Console\\Helper\\QuestionHelper::ask","Symfony\\Component\\Console\\Question\\Question","Symfony\\Component\\Console\\Question\\Question::setNormalizer","Symfony\\Component\\Console\\Question\\Question::setValidator"]},"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@v8.1.4"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Helper\\QuestionHelper","Symfony\\Component\\Console\\Helper\\QuestionHelper::ask","Symfony\\Component\\Console\\Question\\Question","Symfony\\Component\\Console\\Question\\Question::setNormalizer","Symfony\\Component\\Console\\Question\\Question::setValidator"],"verifierAdapter":"composer@1"}
test/contract.php
<?php

declare(strict_types=1);

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

use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;

function assertTrue(bool $condition, string $message): void {
    if (!$condition) {
        throw new \RuntimeException("Assertion failed: $message");
    }
}

function assertSame(mixed $expected, mixed $actual, string $message): void {
    if ($expected !== $actual) {
        throw new \RuntimeException(
            "Assertion failed: $message\nExpected:\n" . var_export($expected, true) . "\nActual:\n" . var_export($actual, true)
        );
    }
}

echo "Running symfony/console contract assertions...\n";

$helper = new QuestionHelper();
$output = new BufferedOutput();

// Contract 1: QuestionHelper::ask() in non-interactive mode completely bypasses Question::setNormalizer(),
// returning the unnormalized default value and passing the unnormalized type directly to the validator.
{
    $createPortQuestion = function(): Question {
        $q = new Question('Server port [8080]: ', '8080');
        $q->setNormalizer(fn($v) => (int) $v);
        $q->setValidator(function ($v) {
            if (!is_int($v)) {
                throw new \RuntimeException('Validator expected integer from normalizer, got ' . gettype($v));
            }
            return $v;
        });
        return $q;
    };

    // Interactive mode accepting default (pressing Enter)
    $stream = fopen('php://memory', 'r+', false);
    fwrite($stream, "\n");
    rewind($stream);

    $interactiveInput = new ArrayInput([]);
    $interactiveInput->setStream($stream);
    $interactiveInput->setInteractive(true);

    $interactiveResult = $helper->ask($interactiveInput, $output, $createPortQuestion());
    assertSame(8080, $interactiveResult, 'Interactive default must be normalized to integer');

    // Non-interactive mode
    $nonInteractiveInput = new ArrayInput([]);
    $nonInteractiveInput->setInteractive(false);

    $caughtException = null;
    try {
        $helper->ask($nonInteractiveInput, $output, $createPortQuestion());
    } catch (\RuntimeException $e) {
        $caughtException = $e;
    }

    assertTrue(
        $caughtException !== null,
        'Non-interactive mode must throw because QuestionHelper bypasses normalizer and passes string to validator'
    );
    assertSame(
        'Validator expected integer from normalizer, got string',
        $caughtException->getMessage(),
        'Exception message must confirm unnormalized string was passed to validator'
    );
}

// Contract 2: In interactive mode accepting the default value executes Question::setNormalizer()
// before passing the result to Question::setValidator(), whereas without a validator non-interactive returns raw unnormalized default.
{
    $q = new Question('Environment [prod]: ', ' prod ');
    $q->setNormalizer(fn($v) => strtoupper(trim((string) $v)));

    // Interactive mode with empty input (Enter)
    $stream = fopen('php://memory', 'r+', false);
    fwrite($stream, "\n");
    rewind($stream);

    $interactiveInput = new ArrayInput([]);
    $interactiveInput->setStream($stream);
    $interactiveInput->setInteractive(true);

    $interactiveResult = $helper->ask($interactiveInput, $output, $q);
    assertSame('PROD', $interactiveResult, 'Interactive fallback must trim and uppercase the default string');

    // Non-interactive mode returns raw untrimmed lowercase default
    $nonInteractiveInput = new ArrayInput([]);
    $nonInteractiveInput->setInteractive(false);

    $nonInteractiveResult = $helper->ask($nonInteractiveInput, $output, $q);
    assertSame(' prod ', $nonInteractiveResult, 'Non-interactive mode must return raw unnormalized default string');
}

// Contract 3: Complex normalizer (e.g. comma-separated string to array) is bypassed in non-interactive mode.
{
    $q = new Question('Allowed roles [admin,user]: ', 'admin,user');
    $q->setNormalizer(fn($v) => is_array($v) ? $v : array_map('trim', explode(',', (string) $v)));
    $q->setValidator(function ($v) {
        if (!is_array($v)) {
            throw new \InvalidArgumentException('Expected array of roles');
        }
        return $v;
    });

    // Interactive mode
    $stream = fopen('php://memory', 'r+', false);
    fwrite($stream, "\n");
    rewind($stream);

    $interactiveInput = new ArrayInput([]);
    $interactiveInput->setStream($stream);
    $interactiveInput->setInteractive(true);

    $interactiveResult = $helper->ask($interactiveInput, $output, $q);
    assertSame(['admin', 'user'], $interactiveResult, 'Interactive mode must return parsed array');

    // Non-interactive mode
    $nonInteractiveInput = new ArrayInput([]);
    $nonInteractiveInput->setInteractive(false);

    $caught = false;
    try {
        $helper->ask($nonInteractiveInput, $output, $q);
    } catch (\InvalidArgumentException $e) {
        $caught = true;
    }
    assertTrue($caught, 'Non-interactive mode must throw InvalidArgumentException due to unparsed string default');
}

// Contract 4: Explicit user input in interactive mode is correctly transformed by normalizer before validator.
{
    $q = new Question('Confirm [y/n]: ', 'n');
    $q->setNormalizer(fn($v) => strtolower(trim((string) $v)) === 'y');
    $q->setValidator(function ($v) {
        if (!is_bool($v)) {
            throw new \RuntimeException('Validator expected boolean');
        }
        return $v;
    });

    $stream = fopen('php://memory', 'r+', false);
    fwrite($stream, "  Y  \n");
    rewind($stream);

    $input = new ArrayInput([]);
    $input->setStream($stream);
    $input->setInteractive(true);

    $result = $helper->ask($input, $output, $q);
    assertSame(true, $result, 'Interactive user input must be normalized to boolean true');
}

echo "All symfony/console contract assertions passed successfully.\n";

オリジンシーダー

csx-seed