Skip to content

Commit aa502ff

Browse files
committed
Old-style constructors are no longer supported on PHP 8
1 parent 59c0423 commit aa502ff

14 files changed

+127
-4
lines changed

build/baseline-7.4.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,6 @@ parameters:
8989
count: 1
9090
path: ../src/Reflection/ReflectionProvider/SetterReflectionProviderProvider.php
9191
-
92-
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:259 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
92+
message: "#^Class class@anonymous/src/Testing/TestCase\\.php\\:262 has an uninitialized property \\$reflectionProvider\\. Give it default value or assign it in the constructor\\.$#"
9393
count: 1
9494
path: ../src/Testing/TestCase.php

src/Analyser/NodeScopeResolver.php

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
use PHPStan\Node\ReturnStatement;
6868
use PHPStan\Node\UnreachableStatementNode;
6969
use PHPStan\Parser\Parser;
70+
use PHPStan\Php\PhpVersion;
7071
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
7172
use PHPStan\PhpDoc\ResolvedPhpDocBlock;
7273
use PHPStan\PhpDoc\Tag\ParamTag;
@@ -125,6 +126,8 @@ class NodeScopeResolver
125126

126127
private \PHPStan\Type\FileTypeMapper $fileTypeMapper;
127128

129+
private PhpVersion $phpVersion;
130+
128131
private \PHPStan\PhpDoc\PhpDocInheritanceResolver $phpDocInheritanceResolver;
129132

130133
private \PHPStan\File\FileHelper $fileHelper;
@@ -166,6 +169,7 @@ public function __construct(
166169
ClassReflectionExtensionRegistryProvider $classReflectionExtensionRegistryProvider,
167170
Parser $parser,
168171
FileTypeMapper $fileTypeMapper,
172+
PhpVersion $phpVersion,
169173
PhpDocInheritanceResolver $phpDocInheritanceResolver,
170174
FileHelper $fileHelper,
171175
TypeSpecifier $typeSpecifier,
@@ -181,6 +185,7 @@ public function __construct(
181185
$this->classReflectionExtensionRegistryProvider = $classReflectionExtensionRegistryProvider;
182186
$this->parser = $parser;
183187
$this->fileTypeMapper = $fileTypeMapper;
188+
$this->phpVersion = $phpVersion;
184189
$this->phpDocInheritanceResolver = $phpDocInheritanceResolver;
185190
$this->fileHelper = $fileHelper;
186191
$this->typeSpecifier = $typeSpecifier;
@@ -544,6 +549,7 @@ private function processStmtNode(
544549
$classReflection = new ClassReflection(
545550
$this->reflectionProvider,
546551
$this->fileTypeMapper,
552+
$this->phpVersion,
547553
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
548554
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
549555
$betterReflectionClass->getName(),

src/Php/PhpVersion.php

+5
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,9 @@ public function supportsClassConstantOnExpression(): bool
7171
return $this->versionId >= 80000;
7272
}
7373

74+
public function supportsLegacyConstructor(): bool
75+
{
76+
return $this->versionId < 80000;
77+
}
78+
7479
}

src/Reflection/BetterReflection/BetterReflectionProvider.php

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use PHPStan\DependencyInjection\Reflection\ClassReflectionExtensionRegistryProvider;
99
use PHPStan\File\FileHelper;
1010
use PHPStan\File\RelativePathHelper;
11+
use PHPStan\Php\PhpVersion;
1112
use PHPStan\PhpDoc\StubPhpDocProvider;
1213
use PHPStan\PhpDoc\Tag\ParamTag;
1314
use PHPStan\Reflection\ClassReflection;
@@ -47,6 +48,8 @@ class BetterReflectionProvider implements ReflectionProvider
4748

4849
private \PHPStan\Type\FileTypeMapper $fileTypeMapper;
4950

51+
private PhpVersion $phpVersion;
52+
5053
private \PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider $nativeFunctionReflectionProvider;
5154

5255
private StubPhpDocProvider $stubPhpDocProvider;
@@ -75,6 +78,7 @@ public function __construct(
7578
ClassReflectionExtensionRegistryProvider $classReflectionExtensionRegistryProvider,
7679
ClassReflector $classReflector,
7780
FileTypeMapper $fileTypeMapper,
81+
PhpVersion $phpVersion,
7882
NativeFunctionReflectionProvider $nativeFunctionReflectionProvider,
7983
StubPhpDocProvider $stubPhpDocProvider,
8084
FunctionReflectionFactory $functionReflectionFactory,
@@ -90,6 +94,7 @@ public function __construct(
9094
$this->classReflectionExtensionRegistryProvider = $classReflectionExtensionRegistryProvider;
9195
$this->classReflector = $classReflector;
9296
$this->fileTypeMapper = $fileTypeMapper;
97+
$this->phpVersion = $phpVersion;
9398
$this->nativeFunctionReflectionProvider = $nativeFunctionReflectionProvider;
9499
$this->stubPhpDocProvider = $stubPhpDocProvider;
95100
$this->functionReflectionFactory = $functionReflectionFactory;
@@ -138,6 +143,7 @@ public function getClass(string $className): ClassReflection
138143
$classReflection = new ClassReflection(
139144
$this->reflectionProviderProvider->getReflectionProvider(),
140145
$this->fileTypeMapper,
146+
$this->phpVersion,
141147
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
142148
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
143149
$reflectionClass->getName(),
@@ -209,6 +215,7 @@ public function getAnonymousClassReflection(\PhpParser\Node\Stmt\Class_ $classNo
209215
self::$anonymousClasses[$className] = new ClassReflection(
210216
$this->reflectionProviderProvider->getReflectionProvider(),
211217
$this->fileTypeMapper,
218+
$this->phpVersion,
212219
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
213220
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
214221
sprintf('class@anonymous/%s:%s', $filename, $classNode->getLine()),

src/Reflection/ClassReflection.php

+27-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPStan\Reflection;
44

5+
use PHPStan\Php\PhpVersion;
56
use PHPStan\PhpDoc\ResolvedPhpDocBlock;
67
use PHPStan\PhpDoc\Tag\ExtendsTag;
78
use PHPStan\PhpDoc\Tag\ImplementsTag;
@@ -20,6 +21,7 @@
2021
use PHPStan\Type\Generic\TemplateTypeScope;
2122
use PHPStan\Type\Type;
2223
use PHPStan\Type\VerbosityLevel;
24+
use ReflectionMethod;
2325

2426
class ClassReflection implements ReflectionWithFilename
2527
{
@@ -28,6 +30,8 @@ class ClassReflection implements ReflectionWithFilename
2830

2931
private \PHPStan\Type\FileTypeMapper $fileTypeMapper;
3032

33+
private PhpVersion $phpVersion;
34+
3135
/** @var \PHPStan\Reflection\PropertiesClassReflectionExtension[] */
3236
private array $propertiesClassReflectionExtensions;
3337

@@ -97,6 +101,7 @@ class ClassReflection implements ReflectionWithFilename
97101
public function __construct(
98102
ReflectionProvider $reflectionProvider,
99103
FileTypeMapper $fileTypeMapper,
104+
PhpVersion $phpVersion,
100105
array $propertiesClassReflectionExtensions,
101106
array $methodsClassReflectionExtensions,
102107
string $displayName,
@@ -109,6 +114,7 @@ public function __construct(
109114
{
110115
$this->reflectionProvider = $reflectionProvider;
111116
$this->fileTypeMapper = $fileTypeMapper;
117+
$this->phpVersion = $phpVersion;
112118
$this->propertiesClassReflectionExtensions = $propertiesClassReflectionExtensions;
113119
$this->methodsClassReflectionExtensions = $methodsClassReflectionExtensions;
114120
$this->displayName = $displayName;
@@ -406,18 +412,36 @@ public function getNativeMethods(): array
406412

407413
public function hasConstructor(): bool
408414
{
409-
return $this->reflection->getConstructor() !== null;
415+
return $this->findConstructor() !== null;
410416
}
411417

412418
public function getConstructor(): MethodReflection
413419
{
414-
$constructor = $this->reflection->getConstructor();
420+
$constructor = $this->findConstructor();
415421
if ($constructor === null) {
416422
throw new \PHPStan\ShouldNotHappenException();
417423
}
418424
return $this->getNativeMethod($constructor->getName());
419425
}
420426

427+
private function findConstructor(): ?ReflectionMethod
428+
{
429+
$constructor = $this->reflection->getConstructor();
430+
if ($constructor === null) {
431+
return null;
432+
}
433+
434+
if ($this->phpVersion->supportsLegacyConstructor()) {
435+
return $constructor;
436+
}
437+
438+
if (strtolower($constructor->getName()) !== '__construct') {
439+
return null;
440+
}
441+
442+
return $constructor;
443+
}
444+
421445
private function getPhpExtension(): PhpClassReflectionExtension
422446
{
423447
$extension = $this->methodsClassReflectionExtensions[0];
@@ -839,6 +863,7 @@ public function withTypes(array $types): self
839863
return new self(
840864
$this->reflectionProvider,
841865
$this->fileTypeMapper,
866+
$this->phpVersion,
842867
$this->propertiesClassReflectionExtensions,
843868
$this->methodsClassReflectionExtensions,
844869
$this->displayName,

src/Reflection/Runtime/RuntimeReflectionProvider.php

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use PhpParser\Node;
66
use PHPStan\Analyser\Scope;
77
use PHPStan\DependencyInjection\Reflection\ClassReflectionExtensionRegistryProvider;
8+
use PHPStan\Php\PhpVersion;
89
use PHPStan\PhpDoc\StubPhpDocProvider;
910
use PHPStan\PhpDoc\Tag\ParamTag;
1011
use PHPStan\Reflection\ClassReflection;
@@ -34,6 +35,8 @@ class RuntimeReflectionProvider implements ReflectionProvider
3435

3536
private \PHPStan\Type\FileTypeMapper $fileTypeMapper;
3637

38+
private PhpVersion $phpVersion;
39+
3740
private \PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider $nativeFunctionReflectionProvider;
3841

3942
private StubPhpDocProvider $stubPhpDocProvider;
@@ -57,6 +60,7 @@ public function __construct(
5760
ClassReflectionExtensionRegistryProvider $classReflectionExtensionRegistryProvider,
5861
FunctionReflectionFactory $functionReflectionFactory,
5962
FileTypeMapper $fileTypeMapper,
63+
PhpVersion $phpVersion,
6064
NativeFunctionReflectionProvider $nativeFunctionReflectionProvider,
6165
StubPhpDocProvider $stubPhpDocProvider,
6266
PhpStormStubsSourceStubber $phpStormStubsSourceStubber
@@ -66,6 +70,7 @@ public function __construct(
6670
$this->classReflectionExtensionRegistryProvider = $classReflectionExtensionRegistryProvider;
6771
$this->functionReflectionFactory = $functionReflectionFactory;
6872
$this->fileTypeMapper = $fileTypeMapper;
73+
$this->phpVersion = $phpVersion;
6974
$this->nativeFunctionReflectionProvider = $nativeFunctionReflectionProvider;
7075
$this->stubPhpDocProvider = $stubPhpDocProvider;
7176
$this->phpStormStubsSourceStubber = $phpStormStubsSourceStubber;
@@ -148,6 +153,7 @@ private function getClassFromReflection(\ReflectionClass $reflectionClass, strin
148153
$classReflection = new ClassReflection(
149154
$this->reflectionProviderProvider->getReflectionProvider(),
150155
$this->fileTypeMapper,
156+
$this->phpVersion,
151157
$this->classReflectionExtensionRegistryProvider->getRegistry()->getPropertiesClassReflectionExtensions(),
152158
$this->classReflectionExtensionRegistryProvider->getRegistry()->getMethodsClassReflectionExtensions(),
153159
$displayName,

src/Testing/RuleTestCase.php

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use PHPStan\Dependency\ExportedNodeResolver;
1414
use PHPStan\File\FileHelper;
1515
use PHPStan\File\SimpleRelativePathHelper;
16+
use PHPStan\Php\PhpVersion;
1617
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
1718
use PHPStan\PhpDoc\PhpDocNodeResolver;
1819
use PHPStan\PhpDoc\PhpDocStringResolver;
@@ -74,6 +75,7 @@ private function getAnalyser(): Analyser
7475
$this->getClassReflectionExtensionRegistryProvider(),
7576
$this->getParser(),
7677
$fileTypeMapper,
78+
self::getContainer()->getByType(PhpVersion::class),
7779
$phpDocInheritanceResolver,
7880
$fileHelper,
7981
$typeSpecifier,

src/Testing/TestCase.php

+2
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ private function createRuntimeReflectionProvider(ReflectionProvider $actualRefle
221221
$classReflectionExtensionRegistryProvider,
222222
$functionReflectionFactory,
223223
$fileTypeMapper,
224+
self::getContainer()->getByType(PhpVersion::class),
224225
self::getContainer()->getByType(NativeFunctionReflectionProvider::class),
225226
self::getContainer()->getByType(StubPhpDocProvider::class),
226227
self::getContainer()->getByType(PhpStormStubsSourceStubber::class)
@@ -373,6 +374,7 @@ private function createStaticReflectionProvider(): ReflectionProvider
373374
$classReflectionExtensionRegistryProvider,
374375
$classReflector,
375376
$fileTypeMapper,
377+
self::getContainer()->getByType(PhpVersion::class),
376378
self::getContainer()->getByType(NativeFunctionReflectionProvider::class),
377379
self::getContainer()->getByType(StubPhpDocProvider::class),
378380
$functionReflectionFactory,

tests/PHPStan/Analyser/AnalyserTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use PHPStan\NodeVisitor\StatementOrderVisitor;
1313
use PHPStan\Parser\DirectParser;
1414
use PHPStan\Parser\NodeChildrenVisitor;
15+
use PHPStan\Php\PhpVersion;
1516
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
1617
use PHPStan\PhpDoc\PhpDocNodeResolver;
1718
use PHPStan\PhpDoc\PhpDocStringResolver;
@@ -506,6 +507,7 @@ private function createAnalyser(bool $reportUnmatchedIgnoredErrors): \PHPStan\An
506507
$this->getClassReflectionExtensionRegistryProvider(),
507508
$this->getParser(),
508509
$fileTypeMapper,
510+
self::getContainer()->getByType(PhpVersion::class),
509511
$phpDocInheritanceResolver,
510512
$fileHelper,
511513
$typeSpecifier,

tests/PHPStan/Analyser/NodeScopeResolverTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPStan\File\FileHelper;
1515
use PHPStan\File\SimpleRelativePathHelper;
1616
use PHPStan\Node\VirtualNode;
17+
use PHPStan\Php\PhpVersion;
1718
use PHPStan\PhpDoc\PhpDocInheritanceResolver;
1819
use PHPStan\PhpDoc\PhpDocNodeResolver;
1920
use PHPStan\PhpDoc\PhpDocStringResolver;
@@ -10917,6 +10918,7 @@ private function processFile(
1091710918
$this->getClassReflectionExtensionRegistryProvider(),
1091810919
$this->getParser(),
1091910920
$fileTypeMapper,
10921+
self::getContainer()->getByType(PhpVersion::class),
1092010922
$phpDocInheritanceResolver,
1092110923
$fileHelper,
1092210924
$typeSpecifier,

tests/PHPStan/Broker/BrokerTest.php

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPStan\DependencyInjection\Type\DirectOperatorTypeSpecifyingExtensionRegistryProvider;
1111
use PHPStan\File\FileHelper;
1212
use PHPStan\File\SimpleRelativePathHelper;
13+
use PHPStan\Php\PhpVersion;
1314
use PHPStan\PhpDoc\PhpDocNodeResolver;
1415
use PHPStan\PhpDoc\PhpDocStringResolver;
1516
use PHPStan\PhpDoc\StubPhpDocProvider;
@@ -46,6 +47,7 @@ protected function setUp(): void
4647
$classReflectionExtensionRegistryProvider,
4748
$this->createMock(FunctionReflectionFactory::class),
4849
new FileTypeMapper($setterReflectionProviderProvider, $this->getParser(), $phpDocStringResolver, $phpDocNodeResolver, $this->createMock(Cache::class), $anonymousClassNameHelper),
50+
self::getContainer()->getByType(PhpVersion::class),
4951
self::getContainer()->getByType(NativeFunctionReflectionProvider::class),
5052
self::getContainer()->getByType(StubPhpDocProvider::class),
5153
self::getContainer()->getByType(PhpStormStubsSourceStubber::class)

tests/PHPStan/Reflection/ClassReflectionTest.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace PHPStan\Reflection;
44

55
use PHPStan\Broker\Broker;
6+
use PHPStan\Php\PhpVersion;
67
use PHPStan\Type\FileTypeMapper;
78

89
class ClassReflectionTest extends \PHPStan\Testing\TestCase
@@ -26,7 +27,7 @@ public function testHasTraitUse(string $className, bool $has): void
2627
{
2728
$broker = $this->createMock(Broker::class);
2829
$fileTypeMapper = $this->createMock(FileTypeMapper::class);
29-
$classReflection = new ClassReflection($broker, $fileTypeMapper, [], [], $className, new \ReflectionClass($className), null, null, null);
30+
$classReflection = new ClassReflection($broker, $fileTypeMapper, new PhpVersion(PHP_VERSION_ID), [], [], $className, new \ReflectionClass($className), null, null, null);
3031
$this->assertSame($has, $classReflection->hasTraitUse(\HasTraitUse\FooTrait::class));
3132
}
3233

@@ -93,6 +94,7 @@ public function testClassHierarchyDistances(
9394
$classReflection = new ClassReflection(
9495
$broker,
9596
$fileTypeMapper,
97+
new PhpVersion(PHP_VERSION_ID),
9698
[],
9799
[],
98100
$class,

tests/PHPStan/Rules/Classes/InstantiationRuleTest.php

+41
Original file line numberDiff line numberDiff line change
@@ -223,4 +223,45 @@ public function testBug3404(): void
223223
]);
224224
}
225225

226+
public function testOldStyleConstructorOnPhp8(): void
227+
{
228+
if (PHP_VERSION_ID < 80000) {
229+
$this->markTestSkipped('Test requires PHP 8.0');
230+
}
231+
232+
$this->analyse([__DIR__ . '/data/php80-constructor.php'], [
233+
[
234+
'Class OldStyleConstructorOnPhp8 does not have a constructor and must be instantiated without any parameters.',
235+
13,
236+
],
237+
[
238+
'Class OldStyleConstructorOnPhp8 does not have a constructor and must be instantiated without any parameters.',
239+
20,
240+
],
241+
]);
242+
}
243+
244+
public function testOldStyleConstructorOnPhp7(): void
245+
{
246+
if (PHP_VERSION_ID >= 80000) {
247+
$this->markTestSkipped('Test requires PHP 7.x');
248+
}
249+
250+
$errors = [
251+
[
252+
'Class OldStyleConstructorOnPhp8 constructor invoked with 0 parameters, 1 required.',
253+
19,
254+
],
255+
];
256+
257+
if (!self::$useStaticReflectionProvider) {
258+
$errors[] = [
259+
'Methods with the same name as their class will not be constructors in a future version of PHP; OldStyleConstructorOnPhp8 has a deprecated constructor',
260+
3,
261+
];
262+
}
263+
264+
$this->analyse([__DIR__ . '/data/php80-constructor.php'], $errors);
265+
}
266+
226267
}

0 commit comments

Comments
 (0)