Skip to content

Commit 5170195

Browse files
committed
Allow mixed type dynamic constants.
Addresses phpstan/phpstan#7520 Revert "Allow mixed type dynamic constants." This reverts commit 1854985. Allow setting types for dynamic constants Unit test fixes Unit test fix 2 Lint fixes Use TypeStringResolver directly Remove old code
1 parent 4afa27b commit 5170195

File tree

9 files changed

+64
-8
lines changed

9 files changed

+64
-8
lines changed

src/Analyser/ConstantResolver.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace PHPStan\Analyser;
44

55
use PhpParser\Node\Name;
6+
use PHPStan\DependencyInjection\Container;
67
use PHPStan\Php\ComposerPhpVersionFactory;
78
use PHPStan\Php\PhpVersion;
9+
use PHPStan\PhpDoc\TypeStringResolver;
810
use PHPStan\Reflection\NamespaceAnswerer;
911
use PHPStan\Reflection\ReflectionProvider;
1012
use PHPStan\Reflection\ReflectionProvider\ReflectionProviderProvider;
@@ -46,6 +48,9 @@ public function __construct(
4648
private array $dynamicConstantNames,
4749
private int|array|null $phpVersion,
4850
private ComposerPhpVersionFactory $composerPhpVersionFactory,
51+
private ?PhpVersion $composerMinPhpVersion,
52+
private ?PhpVersion $composerMaxPhpVersion,
53+
private ?Container $container,
4954
)
5055
{
5156
}
@@ -400,8 +405,17 @@ private function getMaxPhpVersion(): ?PhpVersion
400405

401406
public function resolveConstantType(string $constantName, Type $constantType): Type
402407
{
403-
if ($constantType->isConstantValue()->yes() && in_array($constantName, $this->dynamicConstantNames, true)) {
404-
return $constantType->generalize(GeneralizePrecision::lessSpecific());
408+
if ($constantType->isConstantValue()->yes()) {
409+
if (array_key_exists($constantName, $this->dynamicConstantNames)) {
410+
$phpdocTypes = $this->dynamicConstantNames[$constantName];
411+
$typeStringResolver = $this->container?->getByType(TypeStringResolver::class);
412+
if ($typeStringResolver !== null) {
413+
return $typeStringResolver->resolve($phpdocTypes, new NameScope(null, [], null));
414+
}
415+
}
416+
if (in_array($constantName, $this->dynamicConstantNames, true)) {
417+
return $constantType->generalize(GeneralizePrecision::lessSpecific());
418+
}
405419
}
406420

407421
return $constantType;
@@ -410,6 +424,20 @@ public function resolveConstantType(string $constantName, Type $constantType): T
410424
public function resolveClassConstantType(string $className, string $constantName, Type $constantType, ?Type $nativeType): Type
411425
{
412426
$lookupConstantName = sprintf('%s::%s', $className, $constantName);
427+
if (array_key_exists($lookupConstantName, $this->dynamicConstantNames)) {
428+
if ($nativeType !== null) {
429+
return $nativeType;
430+
}
431+
432+
if ($constantType->isConstantValue()->yes()) {
433+
$phpdocTypes = $this->dynamicConstantNames[$lookupConstantName];
434+
$typeStringResolver = $this->container?->getByType(TypeStringResolver::class);
435+
if ($typeStringResolver !== null) {
436+
return $typeStringResolver->resolve($phpdocTypes, new NameScope(null, [], $className));
437+
}
438+
}
439+
}
440+
413441
if (in_array($lookupConstantName, $this->dynamicConstantNames, true)) {
414442
if ($nativeType !== null) {
415443
return $nativeType;

src/Analyser/ConstantResolverFactory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ public function create(): ConstantResolver
2525
$this->container->getParameter('dynamicConstantNames'),
2626
$this->container->getParameter('phpVersion'),
2727
$composerFactory,
28+
$composerFactory->getMinVersion(),
29+
$composerFactory->getMaxVersion(),
30+
$this->container,
2831
);
2932
}
3033

src/Analyser/MutatingScope.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5670,6 +5670,11 @@ public function getConstantReflection(Type $typeWithConstant, string $constantNa
56705670
return $typeWithConstant->getConstant($constantName);
56715671
}
56725672

5673+
public function getConstantExplicitTypeFromConfig(string $constantName, Type $constantType): Type
5674+
{
5675+
return $this->constantResolver->resolveConstantType($constantName, $constantType);
5676+
}
5677+
56735678
/**
56745679
* @return array<string, ExpressionTypeHolder>
56755680
*/

src/Analyser/Scope.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ public function getMethodReflection(Type $typeWithMethod, string $methodName): ?
8181

8282
public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ClassConstantReflection;
8383

84+
public function getConstantExplicitTypeFromConfig(string $constantName, Type $constantType): Type;
85+
8486
public function getIterableKeyType(Type $iteratee): Type;
8587

8688
public function getIterableValueType(Type $iteratee): Type;

src/DependencyInjection/ValidateIgnoredErrorsExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function loadConfiguration(): void
6767
ReflectionProviderStaticAccessor::registerInstance($reflectionProvider);
6868
PhpVersionStaticAccessor::registerInstance(new PhpVersion(PHP_VERSION_ID));
6969
$composerPhpVersionFactory = new ComposerPhpVersionFactory([]);
70-
$constantResolver = new ConstantResolver($reflectionProviderProvider, [], null, $composerPhpVersionFactory);
70+
$constantResolver = new ConstantResolver($reflectionProviderProvider, [], null, $composerPhpVersionFactory, null, null, null);
7171

7272
$phpDocParserConfig = new ParserConfig([]);
7373
$ignoredRegexValidator = new IgnoredRegexValidator(

src/Testing/PHPStanTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ public static function createScopeFactory(ReflectionProvider $reflectionProvider
139139

140140
$reflectionProviderProvider = new DirectReflectionProviderProvider($reflectionProvider);
141141
$composerPhpVersionFactory = $container->getByType(ComposerPhpVersionFactory::class);
142-
$constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames, null, $composerPhpVersionFactory);
142+
$constantResolver = new ConstantResolver($reflectionProviderProvider, $dynamicConstantNames, null, $composerPhpVersionFactory, null, null, $container);
143143

144144
$initializerExprTypeResolver = new InitializerExprTypeResolver(
145145
$constantResolver,

src/Type/Php/DefineConstantTypeSpecifyingExtension.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,17 @@ public function specifyTypes(
5050
return new SpecifiedTypes([], []);
5151
}
5252

53+
$valueType = $scope->getType($node->getArgs()[1]->value);
54+
$finalType = $scope->getConstantExplicitTypeFromConfig(
55+
$constantName->getValue(),
56+
$valueType,
57+
);
58+
5359
return $this->typeSpecifier->create(
5460
new Node\Expr\ConstFetch(
5561
new Node\Name\FullyQualified($constantName->getValue()),
5662
),
57-
$scope->getType($node->getArgs()[1]->value),
63+
$finalType,
5864
TypeSpecifierContext::createTruthy(),
5965
$scope,
6066
)->setAlwaysOverwriteTypes();

tests/PHPStan/Analyser/LegacyNodeScopeResolverTest.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8450,6 +8450,10 @@ public function dataDynamicConstants(): array
84508450
'string',
84518451
'DynamicConstants\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
84528452
],
8453+
[
8454+
'string|null',
8455+
'DynamicConstants\DynamicConstantClass::DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS',
8456+
],
84538457
[
84548458
"'abc123def'",
84558459
'DynamicConstants\DynamicConstantClass::PURE_CONSTANT_IN_CLASS',
@@ -8459,13 +8463,17 @@ public function dataDynamicConstants(): array
84598463
'DynamicConstants\NoDynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
84608464
],
84618465
[
8462-
'false',
8466+
'bool',
84638467
'GLOBAL_DYNAMIC_CONSTANT',
84648468
],
84658469
[
84668470
'123',
84678471
'GLOBAL_PURE_CONSTANT',
84688472
],
8473+
[
8474+
'string|null',
8475+
'GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES',
8476+
],
84698477
];
84708478
}
84718479

@@ -8483,8 +8491,10 @@ public function testDynamicConstants(
84838491
$expression,
84848492
'die',
84858493
[
8486-
'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
8487-
'GLOBAL_DYNAMIC_CONSTANT',
8494+
0 => 'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_IN_CLASS',
8495+
1 => 'GLOBAL_DYNAMIC_CONSTANT',
8496+
'DynamicConstants\\DynamicConstantClass::DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS' => 'string|null',
8497+
'GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES' => 'string|null',
84888498
],
84898499
);
84908500
}

tests/PHPStan/Analyser/data/dynamic-constant.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
define('GLOBAL_PURE_CONSTANT', 123);
66
define('GLOBAL_DYNAMIC_CONSTANT', false);
7+
define('GLOBAL_DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES', null);
78

89
class DynamicConstantClass
910
{
1011
const DYNAMIC_CONSTANT_IN_CLASS = 'abcdef';
12+
const DYNAMIC_CONSTANT_WITH_EXPLICIT_TYPES_IN_CLASS = 'xyz';
1113
const PURE_CONSTANT_IN_CLASS = 'abc123def';
1214
}
1315

0 commit comments

Comments
 (0)