-
Notifications
You must be signed in to change notification settings - Fork 574
Suppress undefined static property error when property_exists() guard is present
#5544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
06e9479
7695489
42ffe26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| namespace Bug2861Nsrt; | ||
|
|
||
| use function PHPStan\Testing\assertType; | ||
|
|
||
| /** | ||
| * @param object|string $objectOrClass | ||
| */ | ||
| function testObjectOrString($objectOrClass): void { | ||
| if (property_exists($objectOrClass, 'foo')) { | ||
| assertType('class-string|(object&hasProperty(foo))', $objectOrClass); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @param object|class-string $objectOrClass | ||
| */ | ||
| function testObjectOrClassString($objectOrClass): void { | ||
| if (property_exists($objectOrClass, 'bar')) { | ||
| assertType('class-string|(object&hasProperty(bar))', $objectOrClass); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| namespace Bug2861Assign; | ||
|
|
||
| class Foo { | ||
| public static function test(): void { | ||
| if (property_exists(static::class, 'default')) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should also test non-static property fetches, like in https://phpstan.org/r/20ab67ef-ef8b-4f24-8783-1ff18cfe7168
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. Added non-static (instance) property fetch test cases as requested by staabm:
All 12131 tests pass and |
||
| static::$default = 'value'; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @param class-string $className | ||
| */ | ||
| public static function testExpr(string $className): void { | ||
| if (property_exists($className, 'default')) { | ||
| $className::$default = 'value'; | ||
| } | ||
| } | ||
|
|
||
| public function testInstance(): void { | ||
| if (property_exists($this, 'default')) { | ||
| $this->default = 'value'; | ||
| } | ||
| } | ||
|
|
||
| /** @param self $obj */ | ||
| public function testInstanceObj(self $obj): void { | ||
| if (property_exists($obj, 'default')) { | ||
| $obj->default = 'value'; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| namespace Bug2861; | ||
|
|
||
| trait EnumTrait { | ||
| /** @var mixed */ | ||
| protected $value; | ||
|
|
||
| /** @param mixed $value */ | ||
| final public function __construct($value) { | ||
| $this->value = $value; | ||
| } | ||
|
|
||
| /** @return static|null */ | ||
| public static function getDefault() { | ||
| if (property_exists(static::class, 'default') && null !== static::$default) { | ||
| $obj = static::$default; | ||
| return new static($obj); | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| class Foo { | ||
| use EnumTrait; | ||
| public const BLA = 'bla'; | ||
| } | ||
|
|
||
| class Bar { | ||
| use EnumTrait; | ||
| public static $default = 'bla'; | ||
| public const BLA = 'bla'; | ||
| } | ||
|
|
||
| class Baz { | ||
| use EnumTrait; | ||
|
|
||
| /** @return static|null */ | ||
| public static function getDefault2() { | ||
| if (property_exists(self::class, 'default') && null !== self::$default) { | ||
| return new static(self::$default); | ||
| } | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| class ExpressionBased { | ||
| /** | ||
| * @param class-string $className | ||
| */ | ||
| public static function test(string $className): void { | ||
| if (property_exists($className, 'default')) { | ||
| echo $className::$default; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| class InstancePropertyAccess { | ||
| public function test(): void { | ||
| if (property_exists($this, 'default')) { | ||
| echo $this->default; | ||
| } | ||
| } | ||
|
|
||
| /** @param self $obj */ | ||
| public function testObj(self $obj): void { | ||
| if (property_exists($obj, 'default')) { | ||
| echo $obj->default; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this if-statement is not covered by a test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed successfully. Here's a summary of what was done:
Addressing staabm's review comments:
Non-static property fetch tests — The remote already had concurrent changes adding
InstancePropertyAccessclass tests (with$thisand$objpatterns) to bothbug-2861.phpandbug-2861-assign.php. I resolved the rebase conflicts keeping those additions.Uncovered
!$objectType->isObject()->yes()branch — Addedtests/PHPStan/Analyser/nsrt/bug-2861.phpwithassertTypetests that exercise theobject|stringnarrowing path inPropertyExistsTypeSpecifyingExtension. This covers the branch where the first argument toproperty_exists()is neither purely string nor purely object, verifying it narrows toclass-string|(object&hasProperty(foo)).