Skip to content
38 changes: 25 additions & 13 deletions src/Type/Php/PropertyExistsTypeSpecifyingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
TypeSpecifierContext $context,
): SpecifiedTypes
{
$propertyNameType = $scope->getType($node->getArgs()[1]->value);
if (!$propertyNameType instanceof ConstantStringType) {
$propertyNameTypes = $scope->getType($node->getArgs()[1]->value)->getConstantStrings();

if ($propertyNameTypes === []) {
return $this->typeSpecifier->create(
new FuncCall(new FullyQualified('property_exists'), $node->getRawArgs()),
new ConstantBooleanType(true),
Expand All @@ -65,34 +66,45 @@
);
}

if ($propertyNameType->getValue() === '') {
return new SpecifiedTypes([], []);
$hasPropertyTypes = [];

Check failure on line 69 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 69 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.
foreach ($propertyNameTypes as $propertyNameType) {
if($propertyNameType->getValue() === '') {
return new SpecifiedTypes([], []);
}

$hasPropertyTypes[] = new HasPropertyType($propertyNameType->getValue());
}

Check failure on line 77 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 77 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (7.4, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.
$objectType = $scope->getType($node->getArgs()[0]->value);
if ($objectType instanceof ConstantStringType) {

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.4)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path /home/runner/work/phpstan-src/phpstan-src/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.

Check failure on line 79 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Ignored error pattern #^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$# (phpstanApi.instanceofType) in path D:\a\phpstan-src\phpstan-src\src\Type\Php\PropertyExistsTypeSpecifyingExtension.php is expected to occur 2 times, but occurred only 1 time.
return new SpecifiedTypes([], []);
} elseif ($objectType->isObject()->yes()) {
$propertyNode = new PropertyFetch(
$node->getArgs()[0]->value,
new Identifier($propertyNameType->getValue()),
);
$propertyNodes = [];

foreach($propertyNameTypes as $propertyNameType) {
$propertyNodes[] = new PropertyFetch(
$node->getArgs()[0]->value,
new Identifier($propertyNameType->getValue()),

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.3)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.4)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan with result cache (8.2)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, ubuntu-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.4, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.0, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.

Check failure on line 87 in src/Type/Php/PropertyExistsTypeSpecifyingExtension.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1, windows-latest)

Parameter #1 $name of class PhpParser\Node\Identifier constructor expects non-empty-string, string given.
);
}
} else {
return new SpecifiedTypes([], []);
}

$propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyNode, $scope);
if ($propertyReflection !== null) {
if (!$propertyReflection->isNative()) {
return new SpecifiedTypes([], []);
foreach($propertyNodes as $propertyNode) {
$propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyNode, $scope);
if ($propertyReflection !== null) {
if (!$propertyReflection->isNative()) {
return new SpecifiedTypes([], []);
}
}
}

return $this->typeSpecifier->create(
$node->getArgs()[0]->value,
new IntersectionType([
new ObjectWithoutClassType(),
new HasPropertyType($propertyNameType->getValue()),
...$hasPropertyTypes,
]),
$context,
$scope,
Expand Down
25 changes: 25 additions & 0 deletions tests/PHPStan/Analyser/nsrt/bug-13304.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Bug13304;

use function PHPStan\Testing\assertType;

function foo(object $foo): void
{
foreach (['qux', 'quux'] as $property) {
if (!property_exists($foo, $property)) {
throw new \Exception;
}

assertType("object&hasProperty(quux)&hasProperty(qux)", $foo);
}
}

function bar(object $bar): void
{
if (!property_exists($bar, '')) {
throw new \Exception;
}

assertType("object", $bar);
}
Loading