Skip to content

Add array-shape return type for localeconv() and shape-based localtime() return type extension - #6031

Merged
VincentLanglet merged 4 commits into
phpstan:2.2.xfrom
phpstan-bot:create-pull-request/patch-piww913
Jul 10, 2026
Merged

Add array-shape return type for localeconv() and shape-based localtime() return type extension#6031
VincentLanglet merged 4 commits into
phpstan:2.2.xfrom
phpstan-bot:create-pull-request/patch-piww913

Conversation

@phpstan-bot

Copy link
Copy Markdown
Collaborator

Summary

localeconv() was typed as returning a bare array, so reading individual entries (e.g. localeconv()['thousands_sep']) produced mixed. This caused false positives such as "should return string but returns mixed" and "Cannot cast mixed to string". The function actually returns a well-defined array shape, so we now express that shape.

Changes

  • resources/functionMap.php: replaced 'localeconv' => ['array'] with the full array shape:
    array{decimal_point: string, thousands_sep: string, int_curr_symbol: string, currency_symbol: string, mon_decimal_point: string, mon_thousands_sep: string, positive_sign: string, negative_sign: string, int_frac_digits: int, frac_digits: int, p_cs_precedes: int, p_sep_by_space: int, n_cs_precedes: int, n_sep_by_space: int, p_sign_posn: int, n_sign_posn: int, grouping: list<int>}.
  • Added src/Type/Php/LocaltimeFunctionDynamicReturnTypeExtension.php for the analogous localtime() function. Its return shape is conditional on the second (associative_array) argument, which a static functionMap entry cannot express:
    • no/false argument → array{int, int, int, int, int, int, int, int, int} (a 9-element list)
    • true argument → array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}
    • unknown bool → union of both shapes
  • Regenerated vendor/attributes.php so the new #[AutowiredService] extension is registered.
  • Added tests/PHPStan/Analyser/nsrt/localeconv.php covering both functions.

Root cause

Several built-in PHP functions that return a fixed associative array were mapped to a bare array in functionMap.php, losing all per-key type information. The pattern is "array-returning builtin typed as plain array". localeconv() is fixed directly in the function map. Its immediate sibling localtime() (the next entry in the map, same locale/time family) had the same problem but its shape depends on an argument, so it needed a dynamic return type extension rather than a static shape.

Test

tests/PHPStan/Analyser/nsrt/localeconv.php asserts:

  • the full localeconv() shape, plus that ['thousands_sep']/['decimal_point'] are string, ['frac_digits'] is int, and ['grouping'] is list<int> (previously mixed).
  • the localtime() list shape for the default/false argument, the associative tm_* shape for true, and the union of both for an unknown bool argument.

Confirmed the localeconv assertions fail (mixed) before the functionMap change and pass after.

Fixes phpstan/phpstan#14949

…time()` return type extension

- Replace the bare `array` return type of `localeconv()` in `resources/functionMap.php` with the full array shape (string keys such as `decimal_point`/`thousands_sep`, int keys such as `frac_digits`, and `grouping: list<int>`), so accessing individual entries yields `string`/`int`/`list<int>` instead of `mixed`.
- Add `LocaltimeFunctionDynamicReturnTypeExtension` for the sibling `localtime()` function, whose shape depends on the `associative_array` argument: a 9-element `list<int>` by default, the `tm_*` associative shape when the argument is `true`, and the union of both when the argument is an unknown bool.
Comment thread tests/PHPStan/Analyser/nsrt/localeconv.php Outdated
Express the documented value ranges (e.g. tm_sec 0-59, tm_hour 0-23)
as int<min, max> instead of a plain int for both the list and
associative localtime() return shapes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@staabm
staabm requested a review from VincentLanglet July 10, 2026 12:04
Comment thread resources/functionMap.php Outdated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Type/Php/LocaltimeFunctionDynamicReturnTypeExtension.php Outdated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@VincentLanglet
VincentLanglet merged commit 6490b8d into phpstan:2.2.x Jul 10, 2026
670 of 674 checks passed
@VincentLanglet
VincentLanglet deleted the create-pull-request/patch-piww913 branch July 10, 2026 15:21
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.

Type-stubs for localeconv is incorrect

3 participants