Skip to content

Commit d7dfaa6

Browse files
phpstan-botclaude
andcommitted
Make getConstants() array keys optional when filter is non-constant
When getConstants() receives a filter argument that isn't a single constant integer value, we can't determine which constants will be included in the result. Mark all keys as optional in this case instead of treating them as always-defined. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 44ef0cd commit d7dfaa6

2 files changed

Lines changed: 12 additions & 1 deletion

File tree

src/Type/Php/ReflectionClassGetConstantsDynamicReturnTypeExtension.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,21 @@ private function resolveGetConstant(MethodCall $methodCall, Scope $scope, array
115115
private function resolveGetConstants(array $classReflections, ?Type $filterType): ?Type
116116
{
117117
$filter = null;
118+
$filterIsUncertain = false;
118119
if ($filterType !== null) {
119120
$filterScalars = $filterType->getConstantScalarValues();
120121
if (count($filterScalars) === 1 && is_int($filterScalars[0])) {
121122
$filter = $filterScalars[0];
123+
} else {
124+
$filterIsUncertain = true;
122125
}
123126
}
124127

125128
$types = [];
126129
foreach ($classReflections as $classReflection) {
127130
$builder = ConstantArrayTypeBuilder::createEmpty();
128131
foreach ($this->getClassConstants($classReflection, $filter) as [$name, $valueType]) {
129-
$builder->setOffsetValueType(new ConstantStringType($name), $valueType);
132+
$builder->setOffsetValueType(new ConstantStringType($name), $valueType, $filterIsUncertain);
130133
}
131134
$types[] = $builder->getArray();
132135
}

tests/PHPStan/Analyser/nsrt/reflection-class-get-constants.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,11 @@ function testGetConstantsWithFilter(ReflectionClass $ref): void
186186
assertType('array{C: 3.14}', $ref->getConstants(\ReflectionClassConstant::IS_PROTECTED));
187187
assertType('array{D: true}', $ref->getConstants(\ReflectionClassConstant::IS_PRIVATE));
188188
}
189+
190+
/**
191+
* @param ReflectionClass<Foo> $ref
192+
*/
193+
function testGetConstantsWithDynamicFilter(ReflectionClass $ref, int $filter): void
194+
{
195+
assertType("array{A?: 1, B?: 'hello', C?: 3.14, D?: true}", $ref->getConstants($filter));
196+
}

0 commit comments

Comments
 (0)