Skip to content

Incorrect @var PDOStatement<int,string> contains unresolvable type #14206

Closed

Description

@zorac

Bug report

When using a PDOStatement with mode PDO::FETCH_COLUMN I want to be able to type the statement with the appropriate type for the column, e.g. @var PDOStatement<int,string>.

For PHPStan versions up to 2.1.38, this works correctly and no errors are reported. From PHPStan 2.1.39 onwards, this now reports:

PHPDoc tag @var contains unresolvable type.
🪪  varTag.unresolvableType

Code snippet that reproduces the problem

https://phpstan.org/r/0122fc0d-29d4-4aa1-8a57-480dc399d1de

Expected output

No errors found.

Did PHPStan help you today? Did it make you happy in any way?

PHPStan is fantastic at helping me find bugs before they even get committed and pushing me in the direction of writing better code.

Activity

  1. VincentLanglet commented on Feb 26, 2026

    @VincentLanglet
    Contributor

    PDOStatement does not seems to be a generic
    https://github.com/phpstan/phpstan-src/blob/ed40e65342856506cbc5e99bccb5853b941169a9/stubs/PDOStatement.stub#L8

    So PDOStatement<int,string> does not make sens currently. (and shouldn't work before even if it was not reported)

  2. staabm commented on Feb 26, 2026

    @staabm
    Contributor

    You could try https://github.com/staabm/phpstan-dba which will infer the types based on db schema

  3. MacGritsch commented on Mar 3, 2026

    @MacGritsch

    Same issue here: https://phpstan.org/r/c085525e-890d-4fc5-b6fd-6df79a8dea72
    This used to work at least in version 2.1.32

  4. MacGritsch commented on Mar 3, 2026

    @MacGritsch

    My quick and dirty solution for my issue is to revert the change that was made in the stubs-file in version 2.1.39

    $phar = new Phar('phpstan.phar');
    $phar->addFromString('stubs/PDOStatement.stub', str_replace('@return Iterator<mixed, array<int|string, mixed>>', '@return Iterator', $phar['stubs/PDOStatement.stub']->getContent()));
    
  5. staabm commented on Mar 4, 2026

    @staabm
    Contributor

    the simplified example from @MacGritsch regressed in 2.1.39 with

    97288da8e82cf4d507a60edf93b2d60a0ab5ec72 is the first bad commit
    commit 97288da8e82cf4d507a60edf93b2d60a0ab5ec72 (HEAD)
    Author: Daniel Fahlke <flyingmana@googlemail.com>
    Date:   Wed Feb 11 09:29:26 2026 +0100
    
        Bleeding edge - Require generics for Iterator, IteratorAggregate, Generator
    
     conf/bleedingEdge.neon                                                     |  1 +
     conf/config.neon                                                           |  1 +
     conf/parametersSchema.neon                                                 |  1 +
     src/Rules/MissingTypehintCheck.php                                         | 10 +++++++++-
     stubs/PDOStatement.stub                                                    |  2 +-
     stubs/runtime/ReflectionAttribute.php                                      |  3 +++
     tests/PHPStan/Analyser/nsrt/bug-8886.php                                   |  2 +-
     tests/PHPStan/Rules/Classes/LocalTypeAliasesRuleTest.php                   |  2 +-
     tests/PHPStan/Rules/Classes/LocalTypeTraitAliasesRuleTest.php              |  2 +-
     tests/PHPStan/Rules/Classes/LocalTypeTraitUseAliasesRuleTest.php           |  2 +-
     tests/PHPStan/Rules/Classes/MethodTagRuleTest.php                          |  2 +-
     tests/PHPStan/Rules/Classes/MethodTagTraitRuleTest.php                     |  2 +-
     tests/PHPStan/Rules/Classes/MethodTagTraitUseRuleTest.php                  |  2 +-
     tests/PHPStan/Rules/Classes/MixinRuleTest.php                              |  6 +++++-
     tests/PHPStan/Rules/Classes/MixinTraitRuleTest.php                         |  2 +-
     tests/PHPStan/Rules/Classes/MixinTraitUseRuleTest.php                      |  2 +-
     tests/PHPStan/Rules/Classes/PropertyTagRuleTest.php                        |  2 +-
     tests/PHPStan/Rules/Classes/PropertyTagTraitRuleTest.php                   |  2 +-
     tests/PHPStan/Rules/Classes/PropertyTagTraitUseRuleTest.php                |  2 +-
     tests/PHPStan/Rules/Constants/MissingClassConstantTypehintRuleTest.php     |  2 +-
     tests/PHPStan/Rules/Functions/MissingFunctionParameterTypehintRuleTest.php |  2 +-
     tests/PHPStan/Rules/Functions/MissingFunctionReturnTypehintRuleTest.php    | 23 ++++++++++++++++++++++-
     tests/PHPStan/Rules/Functions/data/missing-function-return-typehint.php    | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     tests/PHPStan/Rules/Methods/MissingMethodParameterTypehintRuleTest.php     |  2 +-
     tests/PHPStan/Rules/Methods/MissingMethodReturnTypehintRuleTest.php        |  7 ++++++-
     tests/PHPStan/Rules/Methods/MissingMethodSelfOutTypeRuleTest.php           |  2 +-
     tests/PHPStan/Rules/Methods/data/missing-method-return-typehint.php        |  2 +-
     tests/PHPStan/Rules/PhpDoc/FunctionAssertRuleTest.php                      |  2 +-
     tests/PHPStan/Rules/PhpDoc/InvalidPhpDocVarTagTypeRuleTest.php             |  2 +-
     tests/PHPStan/Rules/PhpDoc/MethodAssertRuleTest.php                        |  2 +-
     tests/PHPStan/Rules/Properties/MissingPropertyTypehintRuleTest.php         |  2 +-
     tests/PHPStan/Rules/Properties/SetPropertyHookParameterRuleTest.php        |  2 +-
     32 files changed, 144 insertions(+), 27 deletions(-)
    
  6. added this to the Easy fixes milestone on Mar 4, 2026
  7. added a commit that references this issue on Mar 4, 2026
    c703aa0
  8. VincentLanglet commented on Mar 4, 2026

    @VincentLanglet
    Contributor

    Looking at the bot explanation, I understand more the issue now.

    Something like PDOStatement<int,array<string>> works fine, the issue is related to PDOStatement<int,string> because
    the template of PDOStatement is defined

     * @implements Traversable<array<int|string, mixed>>
     * @implements IteratorAggregate<array<int|string, mixed>>
    

    with getIterator returning Iterator<mixed, array<int|string, mixed>>

    I'm not familiar with PDO Statement. But from my unstanding we'll have

    PDOStatement<int, string>   // with FETCH_COLUMN
    PDOStatement<int, array>    // with FETCH_ASSOC (défaut)
    PDOStatement<int, object>   // with FETCH_OBJ
    

    So it shouldn't be

    Traversable<array<int|string, mixed>>
    

    but

    Traversable<scalar|array|object|null>
    

    and we should just simplify to Traversable<mixed>

    Best would be having the type restricted thanks to setFetchMode ; maybe with
    https://phpstan.org/writing-php-code/phpdocs-basics#change-type-of-current-object-after-calling-a-method

    Until now

    /**
     * @implements Traversable<mixed>
     * @implements IteratorAggregate<mixed>
     */
    class PDOStatement implements Traversable, IteratorAggregate
    {
        /**
         * @return Iterator<mixed>
         */
        public function getIterator() {}
    }
    

    Could work (?) WDYT @staabm

  9. staabm commented on Mar 4, 2026

    @staabm
    Contributor

    staabm/phpstan-dba would resolve the given example

    class Test
    {
    	public function test(PDO $db): void
    	{
    		$statement = $db->prepare('SELECT foo FROM bar');
    		$statement->setFetchMode(PDO::FETCH_COLUMN, 0);
    		$statement->execute();
    	}
    }
    

    and make the types aware to PHPStan without the need for additional inline @vars.


    my feeling is in phpstan-src core we should use dumb-down types which are generic enough to support all possible use-cases.
    since the most php database APIs (like PDO, mysqli, mysql,..) are stateful, its really hard to mirror them - the types depend on the used database backend, the global configuration of PDO etc (e.g. there is a global fetch mode).
    thats why phpstan-dba exists in the first place.

    I think we should strip down the builtin stub as much as necessary so it works with all relevant use-cases out of the box and tell people to use phpstan-dba when they want more magic/precise types out of the box.

  10. phpstan-bot commented on Mar 6, 2026

    @phpstan-bot
    Contributor

    Closed via merging phpstan/phpstan-src#5132

  11. github-actions commented on Apr 7, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

  12. locked as resolved and limited conversation to collaborators on Apr 7, 2026
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

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions