Fix phpstan/phpstan#14393: Does not warn about non-nullable class-property#5327
Conversation
VincentLanglet
left a comment
There was a problem hiding this comment.
Add test for
public int $i;
|
Done. Here's what I changed to address the review:
|
VincentLanglet
left a comment
There was a problem hiding this comment.
Add test for
$this->i ?? -1
inside both MyClass and MyClassUninitialized
|
The commit has already been pushed. The review request has been addressed — |
VincentLanglet
left a comment
There was a problem hiding this comment.
Add test for
/** @var int */
public $i;
and for
public ?int $i;
and for
public ?int $i = 10;
and for
public ?int $i = null;
|
|
| if (PHP_VERSION_ID < 80100) { | ||
| $errors[] = [ | ||
| 'Property ReflectionClass<object>::$name (class-string<object>) on left side of ?? is not nullable.', | ||
| 136, | ||
| ]; | ||
| } |
There was a problem hiding this comment.
make tests also passed — all 11687 tests green. The review feedback has been fully addressed, committed, and pushed.
VincentLanglet
left a comment
There was a problem hiding this comment.
Add non regression test for phpstan/phpstan#4846
|
Already handled — |
|
I was not sure about the phpdoc case but it's already reported https://phpstan.org/r/190c6781-3043-4ccd-bcf6-9bf2a37b3d91. Maybe you'll see more test to add but this seems ok to me @staabm |
… instance properties - Removed bail-out in IssetCheck for native-typed instance properties accessed on non-$this objects - Static properties still bail out (valid lazy initialization pattern with ??=) - $this->prop still respects initialization tracking as before - Updated NullCoalesceRuleTest to always expect warning for ReflectionClass::$name - Updated IssetRuleTest to expect warnings for all native-typed instance properties - Removed unnecessary ?? null in ArrayFindFunctionReturnTypeExtension - New regression test in tests/PHPStan/Rules/Variables/data/bug-14393.php
Properties declared as `public int $i;` (without a default value) can be uninitialized when accessed on external objects, so using ?? on them is valid. Only warn when the property has a default value (guaranteed initialized). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ized Addresses review feedback: tests verify that $this->prop access inside the class does not produce false positive warnings for either initialized or uninitialized typed properties. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For $this->prop access on native-typed properties with a default value, the property is always initialized so ?? on non-nullable types is useless. Only skip the warning for $this->prop when the property has no default value (could be uninitialized). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ties Tests requested by reviewer: `/** @var int */ public $i`, `public ?int $i`, `public ?int $i = 10`, and `public ?int $i = null` — both for $this->prop and external object access. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ReflectionClass::$name has no default value (set in constructor), so on PHP >= 8.1 hasDefaultValue() returns false and the warning is correctly suppressed. Restore the PHP_VERSION_ID < 80100 guard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add tests for isset($this->i) and isset($o->i) across all property variants (initialized, uninitialized, PHPDoc-only, nullable, etc.) as requested by reviewer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8f7b91f to
8ab2b3c
Compare
|
|
||
| public function doFoo(): void | ||
| { | ||
| var_dump(self::$i ?? -1); |
There was a problem hiding this comment.
we are missing a error here, because the static property referenced by self::$i is not nullable
There was a problem hiding this comment.
Done. The fix applies the same hasDefaultValue() check to static properties that was already in place for instance properties. Now self::$i ?? -1 and isset(self::$i) correctly report errors when the static property has a native type and a default value (like public static int $i = 10), while still allowing the bail-out for uninitialized static properties (no default value) or dynamic class references.
Static properties with a native type and a default value (e.g. `public static int $i = 10`) should produce warnings for `self::$i ?? -1` and `isset(self::$i)` since the property is not nullable. Previously all static property fetches were exempt from this check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…l-out When the scope doesn't track the expression type for a native-typed property access, check if $expr->var is undefined before falling through to the type check. This prevents reporting "not nullable" errors when the real issue is an undefined variable. The check only bails out when there's an actual undefined error (non-null return), otherwise falls through to the normal type check. Same pattern applied to StaticPropertyFetch for consistency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
I was able to remove both I'm ok merging this like this (and maybe waiting for a missing error report) but maybe you'll want to try producing an error/addind extra test. |
|
love it. thank you |
…perty (phpstan#5327) Co-authored-by: VincentLanglet <9052536+VincentLanglet@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Vincent Langlet <vincentlanglet@hotmail.fr>
Summary
PHPStan did not warn about using
??on non-nullable native-typed instance properties accessed on objects other than$this. For example,$o->i ?? -1where$iispublic int $i = 10produced no warning, even though the type isint(not nullable).Changes
src/Rules/IssetCheck.phpto only bail out of the native-typed property check for$this->propaccess (where initialization tracking matters) and static properties (where lazy initialization via??=is a valid pattern). Non-$thisinstance property access now falls through to the normal type check.tests/PHPStan/Rules/Variables/NullCoalesceRuleTest.php— theReflectionClass::$namewarning is now expected on all PHP versions (previously only PHP < 8.1).tests/PHPStan/Rules/Variables/IssetRuleTest.php— native-typed instance properties on external objects now all produce warnings.src/Type/Php/ArrayFindFunctionReturnTypeExtension.php— removed unnecessary?? nullonPhpParser\Node\Arg::$valuewhich is always non-null.tests/PHPStan/Rules/Variables/data/bug-14393.php.Root cause
In
IssetCheck::check(), when a property had a native type and the scope didn't explicitly track the expression type ($scope->hasExpressionType($expr)->yes()was false), the code bailed out early for ALL property accesses. This was intended to handle potentially uninitialized typed properties, but it was too conservative — it also suppressed warnings for instance property access on external objects where PHPStan resolves the type as non-nullable.The fix narrows the bail-out to only apply to:
$this->prop— where PHPStan tracks initialization state and the bail-out prevents false positives for possibly-uninitialized properties??=is commonly used for lazy initializationTest
Added
tests/PHPStan/Rules/Variables/data/bug-14393.phpwhich tests$o->i ?? -1where$iispublic int $i = 10. The expected error is: "Property Bug14393\MyClass::$i (int) on left side of ?? is not nullable."Fixes phpstan/phpstan#14393
Closes phpstan/phpstan#4846