Repository: symfony/symfony
File: src/Symfony/Component/HttpFoundation/InputBag.php (PHP)

Code before:
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\HttpFoundation;

use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Exception\UnexpectedValueException;

/**
 * InputBag is a container for user input values such as $_GET, $_POST, $_REQUEST, and $_COOKIE.
 *
 * @template TInput of string|int|float|bool|null
 *
 * @author Saif Eddin Gmati <azjezz@protonmail.com>
 */
final class InputBag extends ParameterBag
{
    /**
     * Returns a scalar input value by name.
     *
     * @template TDefault of TInput|null
     *
     * @param TDefault $default The default value if the input key does not exist
     *
     * @return TDefault|TInput
     *
     * @throws BadRequestException if the input contains a non-scalar value
     */
    public function get(string $key, mixed $default = null): string|int|float|bool|null
    {
        if (null !== $default && !\is_scalar($default) && !$default instanceof \Stringable) {
            throw new \InvalidArgumentException(\sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default)));
        }

        $value = parent::get($key, $this);

        if (null !== $value && $this !== $value && !\is_scalar($value) && !$value instanceof \Stringable) {
            throw new BadRequestException(\sprintf('Input value "%s" contains a non-scalar value.', $key));
        }

        return $this === $value ? $default : $value;
    }

    /**
     * Replaces the current input values by a new set.
     */

Review comment (suggestion):
I think this should be solved using a conditional return type instead of a `TDefault` generic (which might not be inferred properly):

```
@param TInput|null $default

@psalm-return ($default is null ? TInput|null : TInput)
```

We want the static analyzer to properly infer the return type, both when using an explicit default and when omitting it (in both psalm and phpstan).

Note that if we go with @nicolas-grekas's proposal allowing more flexible usages, my proposal need to be adapted or dropped (but testing the effectiveness of the inference in phpstan and psalm should still be done IMO)


Code after:
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\HttpFoundation;

use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\HttpFoundation\Exception\UnexpectedValueException;

/**
 * InputBag is a container for user input values such as $_GET, $_POST, $_REQUEST, and $_COOKIE.
 *
 * @template TInput of string|int|float|bool|null
 *
 * @author Saif Eddin Gmati <azjezz@protonmail.com>
 */
final class InputBag extends ParameterBag
{
    /**
     * Returns a scalar input value by name.
     *
     * @template TDefault of string|int|float|bool|null
     *
     * @param TDefault $default The default value if the input key does not exist
     *
     * @return TDefault|TInput
     *
     * @throws BadRequestException if the input contains a non-scalar value
     */
    public function get(string $key, mixed $default = null): string|int|float|bool|null
    {
        if (null !== $default && !\is_scalar($default) && !$default instanceof \Stringable) {
            throw new \InvalidArgumentException(\sprintf('Expected a scalar value as a 2nd argument to "%s()", "%s" given.', __METHOD__, get_debug_type($default)));
        }

        $value = parent::get($key, $this);

        if (null !== $value && $this !== $value && !\is_scalar($value) && !$value instanceof \Stringable) {
            throw new BadRequestException(\sprintf('Input value "%s" contains a non-scalar value.', $key));
        }

        return $this === $value ? $default : $value;
    }

    /**
     * Replaces the current input values by a new set.
     */