Skip to content

Return list<mixed> from PDOStatement::fetchAll() in function signature map#5643

Open
phpstan-bot wants to merge 5 commits into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-e4psdj6
Open

Return list<mixed> from PDOStatement::fetchAll() in function signature map#5643
phpstan-bot wants to merge 5 commits into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-e4psdj6

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

@phpstan-bot phpstan-bot commented May 11, 2026

…`, and `pg_fetch_all_columns()` in function signature map

- Change PDOStatement::fetchAll() return type from `array` to `list<mixed>` (PHP 8.0+) and from `array|false` to `list<mixed>|false` (pre-8.0) across all four overload variants
- Change pg_fetch_all() return type from `array<non-empty-list<string|null>>` to `list<non-empty-list<string|null>>`
- Change pg_fetch_all_columns() return type from `array|false` to `list<string|null>|false`
- Change sqlite_fetch_all() return type from `array` to `list<mixed>`
- All these functions return sequentially 0-indexed arrays, which are lists by definition
- mysqli_fetch_all / mysqli_result::fetch_all were already correctly typed as `list<array>`
Comment thread tests/PHPStan/Analyser/nsrt/bug-11889.php Outdated
The default overload variant covers all fetch modes including
FETCH_KEY_PAIR and FETCH_GROUP which return associative arrays,
not lists. Only the specific overload variants (FETCH_COLUMN,
FETCH_CLASS, FETCH_FUNC) are guaranteed to return lists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@staabm staabm requested a review from VincentLanglet May 12, 2026 05:46
Comment thread resources/functionMap.php Outdated
Comment thread resources/functionMap.php Outdated
@staabm staabm changed the title Return list<mixed> from PDOStatement::fetchAll(), pg_fetch_all(), and pg_fetch_all_columns() in function signature map Return list<mixed> from PDOStatement::fetchAll() in function signature map May 12, 2026
…changes

These functions should not have their return types narrowed to list:
- pg_fetch_all/pg_fetch_all_columns: revert to original array types
- sqlite_fetch_all: undocumented on php.net, keep as array

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread tests/PHPStan/Analyser/nsrt/bug-11889.php Outdated
… list

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@VincentLanglet VincentLanglet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$stmt->fetchAll(\PDO::FETCH_COLUMN); is a valid call and returns a list.

Since both

$stmt->fetchAll(PDO::FETCH_ASSOC)
$stmt->fetchAll(\PDO::FETCH_COLUMN);

fallback to the same signature, I think we cannot solve this by changing the functionMap, but with a dedicated returnTypeExtension instead.

The function map alone cannot distinguish single-argument calls like
fetchAll(PDO::FETCH_COLUMN) from fetchAll(PDO::FETCH_ASSOC) since both
match the same default signature. This extension inspects the constant
fetch mode value to determine whether the result is a list or array.

Modes with FETCH_GROUP/FETCH_UNIQUE flags or FETCH_KEY_PAIR return
associative arrays (not lists). All other known modes return lists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

Pushed. Here's what I did to address VincentLanglet's review:

Created src/Type/Php/PdoStatementFetchAllReturnTypeExtension.php — a DynamicMethodReturnTypeExtension that inspects the constant fetch mode argument of PDOStatement::fetchAll() to determine whether the result is a list or array:

  • Returns list for modes like FETCH_ASSOC, FETCH_NUM, FETCH_BOTH, FETCH_OBJ, FETCH_COLUMN, FETCH_CLASS, FETCH_NAMED, etc.
  • Returns array (falls back to function map) for FETCH_KEY_PAIR, and any mode with FETCH_GROUP or FETCH_UNIQUE flags set
  • Returns array for no-argument calls or non-constant mode values

This solves the reviewer's concern that fetchAll(PDO::FETCH_COLUMN) and fetchAll(PDO::FETCH_ASSOC) both match the same function map signature but should return different types (both are actually lists, while FETCH_KEY_PAIR/FETCH_GROUP are not).

Updated tests/PHPStan/Analyser/nsrt/bug-11889.php with comprehensive assertions covering single-arg list modes, non-list modes (KEY_PAIR, GROUP|ASSOC, UNIQUE|ASSOC), and multi-arg overload variants.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants