diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 47101ea9fe..527ed0c002 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1647,12 +1647,6 @@ parameters: count: 1 path: src/Type/Php/NumberFormatFunctionDynamicReturnTypeExtension.php - - - message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' - identifier: phpstanApi.instanceofType - count: 2 - path: src/Type/Php/PropertyExistsTypeSpecifyingExtension.php - - message: '#^Doing instanceof PHPStan\\Type\\Constant\\ConstantStringType is error\-prone and deprecated\. Use Type\:\:getConstantStrings\(\) instead\.$#' identifier: phpstanApi.instanceofType diff --git a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php index e62a04d409..5b9c3ee4d2 100644 --- a/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php +++ b/src/Type/Php/PropertyExistsTypeSpecifyingExtension.php @@ -16,7 +16,6 @@ use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\Type\Accessory\HasPropertyType; use PHPStan\Type\Constant\ConstantBooleanType; -use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\FunctionTypeSpecifyingExtension; use PHPStan\Type\IntersectionType; use PHPStan\Type\ObjectWithoutClassType; @@ -55,8 +54,9 @@ public function specifyTypes( 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), @@ -65,24 +65,36 @@ public function specifyTypes( ); } - if ($propertyNameType->getValue() === '') { - return new SpecifiedTypes([], []); + $hasPropertyTypes = []; + foreach ($propertyNameTypes as $propertyNameType) { + $hasPropertyTypes[] = new HasPropertyType($propertyNameType->getValue()); } $objectType = $scope->getType($node->getArgs()[0]->value); - if ($objectType instanceof ConstantStringType) { + + if (!$objectType->isObject()->yes()) { return new SpecifiedTypes([], []); - } elseif ($objectType->isObject()->yes()) { - $propertyNode = new PropertyFetch( + } + + $propertyNodes = []; + + foreach ($propertyNameTypes as $propertyNameType) { + if ($propertyNameType->getValue() === '') { + return new SpecifiedTypes([], []); + } + + $propertyNodes[] = new PropertyFetch( $node->getArgs()[0]->value, new Identifier($propertyNameType->getValue()), ); - } else { - return new SpecifiedTypes([], []); } - $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyNode, $scope); - if ($propertyReflection !== null) { + foreach ($propertyNodes as $propertyNode) { + $propertyReflection = $this->propertyReflectionFinder->findPropertyReflectionFromNode($propertyNode, $scope); + if ($propertyReflection === null) { + continue; + } + if (!$propertyReflection->isNative()) { return new SpecifiedTypes([], []); } @@ -92,7 +104,7 @@ public function specifyTypes( $node->getArgs()[0]->value, new IntersectionType([ new ObjectWithoutClassType(), - new HasPropertyType($propertyNameType->getValue()), + ...$hasPropertyTypes, ]), $context, $scope, diff --git a/tests/PHPStan/Analyser/nsrt/bug-13304.php b/tests/PHPStan/Analyser/nsrt/bug-13304.php new file mode 100644 index 0000000000..0c7f2163b1 --- /dev/null +++ b/tests/PHPStan/Analyser/nsrt/bug-13304.php @@ -0,0 +1,16 @@ +