Skip to content

Narrow types after strlen()#5703

Open
phpstan-bot wants to merge 7 commits into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-97bj22r
Open

Narrow types after strlen()#5703
phpstan-bot wants to merge 7 commits into
phpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-97bj22r

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

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

…ArrayDimFetchCheck` "might not exist" report

- In the `reportMaybes` decomposition loop of `NonexistentOffsetInArrayDimFetchCheck`,
  when flattened union members are checked individually, skip reporting for string types
  with integer offsets where a specific member returns `no` for `hasOffsetValueType`
- The union-level `hasOffsetValueType` already correctly returns `maybe` for these cases;
  the decomposition adds no new information for strings and produces false positives
  when one union member (e.g. empty string) is shorter than the offset
- Example: `(''|':')[0]` — union-level returns `maybe`, decomposition found `''` returns
  `no` for offset 0 and incorrectly escalated to "might not exist" report
- Definitive `no` results (single string, non-integer offset) are unaffected
- Regression test covers the original issue pattern and string union variants
Comment thread src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php Outdated
…uthy context

Revert the rule-level fix that skipped string-with-integer-offset checks
in NonexistentOffsetInArrayDimFetchCheck. Instead, teach the TypeSpecifier
to narrow strlen()/mb_strlen() arguments to non-empty-string when the
result is used in a truthy context. This enables the existing
ConditionalExpressionHolder machinery to propagate the narrowing through
variable assignments like `$len = strlen($x); if ($len > 0)`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/Analyser/TypeSpecifier.php Outdated
…xtension

Extract the inline strlen/mb_strlen non-empty-string narrowing from
TypeSpecifier::specifyTypesInCondition() into a proper
FunctionTypeSpecifyingExtension, following the same pattern as
CountFunctionTypeSpecifyingExtension.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread src/Type/Php/StrlenFunctionTypeSpecifyingExtension.php
@staabm staabm changed the title Skip string-with-integer-offset decomposition in NonexistentOffsetInArrayDimFetchCheck "might not exist" report Narrow types after strlen() May 19, 2026
…texts

Cover all context types: direct truthy/falsey, negation, boolean
and/or, ternary, loose comparison with true/false, mb_strlen, and
non-string input handling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
function nonStringInput($mixed): void
{
if (strlen($mixed)) {
assertType('int|string', $mixed);
Copy link
Copy Markdown
Contributor

@staabm staabm May 19, 2026

Choose a reason for hiding this comment

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

strlen($mixed) will be truethy also for e.g. some float or bool

see https://3v4l.org/F5QAQ#veol

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Pushed. Added test cases for float|string and bool|string inputs to strlen() to verify the extension correctly skips narrowing for non-string types, as the reviewer pointed out that strlen() accepts and returns truthy values for floats and booleans too.

Comment thread tests/PHPStan/Analyser/nsrt/bug-13688.php Outdated
phpstan-bot and others added 2 commits May 19, 2026 05:58
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@staabm staabm requested a review from VincentLanglet May 19, 2026 06:05
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.

2 participants