Skip to content

Fix phpstan/phpstan#14421: Incorrect type narrowing of superglobal with dependent types#5377

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-098ra75
Open

Fix phpstan/phpstan#14421: Incorrect type narrowing of superglobal with dependent types#5377
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-098ra75

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When using isset() on a superglobal array offset (e.g., $_SESSION['a']) with dependent type narrowing, PHPStan incorrectly reported that the offset always exists and is not nullable, even when the code path could bypass the isset() branch.

Changes

  • Extended the conditional expression skip logic in src/Analyser/MutatingScope.php to handle superglobal variables that aren't present in the other branch's expression types
  • Added exprContainsSuperGlobal() helper method to detect whether an expression involves a superglobal variable
  • Added regression test in tests/PHPStan/Rules/Variables/data/bug-14421.php and test method in tests/PHPStan/Rules/Variables/IssetRuleTest.php

Root cause

The fix for phpstan/phpstan#14411 added a check to skip creating conditional expressions when both the expression and its guard exist with certainty in the other branch. However, superglobal variables like $_SESSION are always defined but aren't tracked in expressionTypes unless they've been narrowed by a type specification (e.g., from isset()). When $_SESSION was narrowed in the if-branch but not present in the else-branch's expression types, the skip check failed, causing incorrect conditional expressions to be created. These conditional expressions then incorrectly linked $b's type to $_SESSION's narrowed type, so narrowing $b !== null also incorrectly narrowed $_SESSION.

The fix treats superglobal expressions as always existing with certainty, even when not explicitly tracked in the other branch's expression types.

Test

Added a regression test reproducing the exact scenario from the issue: isset($_SESSION['a']) with a fallback assignment in the else branch, followed by a null check that should not cause the isset() to be flagged as always true.

Fixes phpstan/phpstan#14421

- Extended conditional expression skip logic in MutatingScope to handle
  superglobal variables not present in the other branch's expression types
- Added exprContainsSuperGlobal() helper method to detect superglobal
  expressions for reuse across merge logic
- New regression test in tests/PHPStan/Rules/Variables/data/bug-14421.php
- Root cause: superglobals always exist but aren't tracked in expressionTypes
  unless narrowed, so the dependent type skip check failed to recognize them
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.

1 participant