Skip to content

ParameterBag::keys() stub not applied for Symfony ≥ 7.4 → false-positive is_string() alwaysNarrowedType #510

Description

@laszlomezzei

phpstan-symfony ships a stub correcting Symfony\Component\HttpFoundation\ParameterBag::keys() to @return list<array-key>, but StubFilesExtensionLoader only loads it for symfony/http-foundation < 7.4:

// src/Stubs/Symfony/StubFilesExtensionLoader.php
if ($this->isInstalledVersionBelow('symfony/http-foundation', '7.4.0.0')) {
    $files[] = $stubsDir . '/Symfony/Component/HttpFoundation/ParameterBag.stub';
}

From Symfony 7.4 on, Symfony declares its own @return list<string> on keys(), so PHPStan uses that instead. But that PHPDoc is inaccurate: PHP normalises numeric-string array keys to integers, so keys are int|string at runtime (e.g. ?0[]=x produces the int key 0). Symfony declined to correct it (symfony/symfony#60411).

The result is a false positive: a correct runtime guard over ->keys() is reported as always-true, and removing it reintroduces a real TypeError (a numeric param name → int key passed to a string parameter). This is a regression — the stub made this correct for < 7.4.

Code snippet that reproduces the problem

Not reproducible on phpstan.org/r — it needs the phpstan-symfony extension and symfony/http-foundation >= 7.4. Minimal case:

<?php declare(strict_types=1);

use Symfony\Component\HttpFoundation\Request;

function coreField(string $name): bool { return false; }

function f(Request $request): void
{
    foreach ($request->query->keys() as $key) {
        if (!is_string($key)) {
            continue;
        }
        coreField($key);
    }
}

Run PHPStan (level 8, phpstan-symfony enabled) with symfony/http-foundation >= 7.4.

Expected output

No error — keys() returns list<int|string> at runtime, so is_string($key) is a valid narrowing (as it is on symfony/http-foundation < 7.4, where the stub is applied).

Actual output

Call to function is_string() with string will always evaluate to true.    function.alreadyNarrowedType

Environment

  • phpstan/phpstan-symfony: 2.0.20 (also reproduced on 2.0.x-dev)
  • phpstan/phpstan: 2.2.x — level 8, bleedingEdge (treatPhpDocTypesAsCertain)
  • symfony/http-foundation: 7.4.x and 8.1.x
  • PHP 8.x

Suggested fix

The ParameterBag.stub is still accurate for 7.4+, so keep applying it — e.g. bump the gate from < 7.4.0.0 to < 8.3.0.0 (8.2 still ships the inaccurate PHPDoc). Related: #439 (original report), #443 (the stub).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions