Skip to content

Commit f6526cc

Browse files
committed
Exit as function
1 parent 11853e1 commit f6526cc

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

src/Php/PhpVersion.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,9 @@ public function isCurloptUrlCheckingFileSchemeWithOpenBasedir(): bool
338338
return $this->versionId < 80000;
339339
}
340340

341+
public function hasExitAsFunction(): bool
342+
{
343+
return $this->versionId >= 80400;
344+
}
345+
341346
}

src/Reflection/BetterReflection/BetterReflectionProvider.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use PHPStan\Reflection\InitializerExprContext;
4141
use PHPStan\Reflection\InitializerExprTypeResolver;
4242
use PHPStan\Reflection\NamespaceAnswerer;
43+
use PHPStan\Reflection\Php\ExitFunctionReflection;
4344
use PHPStan\Reflection\Php\PhpFunctionReflection;
4445
use PHPStan\Reflection\ReflectionProvider;
4546
use PHPStan\Reflection\SignatureMap\NativeFunctionReflectionProvider;
@@ -52,6 +53,7 @@
5253
use function array_key_exists;
5354
use function array_map;
5455
use function base64_decode;
56+
use function in_array;
5557
use function sprintf;
5658
use function strtolower;
5759
use const PHP_VERSION_ID;
@@ -264,6 +266,12 @@ public function getFunction(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAn
264266
return $this->functionReflections[$lowerCasedFunctionName];
265267
}
266268

269+
if ($this->phpVersion->hasExitAsFunction()) {
270+
if (in_array($lowerCasedFunctionName, ['exit', 'die'], true)) {
271+
return $this->functionReflections[$lowerCasedFunctionName] = new ExitFunctionReflection($lowerCasedFunctionName);
272+
}
273+
}
274+
267275
$nativeFunctionReflection = $this->nativeFunctionReflectionProvider->findFunctionReflection($lowerCasedFunctionName);
268276
if ($nativeFunctionReflection !== null) {
269277
$this->functionReflections[$lowerCasedFunctionName] = $nativeFunctionReflection;
@@ -343,6 +351,12 @@ private function getCustomFunction(string $functionName): PhpFunctionReflection
343351

344352
public function resolveFunctionName(Node\Name $nameNode, ?NamespaceAnswerer $namespaceAnswerer): ?string
345353
{
354+
if ($this->phpVersion->hasExitAsFunction()) {
355+
$name = $nameNode->toLowerString();
356+
if (in_array($name, ['exit', 'die'], true)) {
357+
return $name;
358+
}
359+
}
346360
return $this->resolveName($nameNode, function (string $name): bool {
347361
try {
348362
$this->reflector->reflectFunction($name);
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Reflection\Php;
4+
5+
use PHPStan\Reflection\Assertions;
6+
use PHPStan\Reflection\FunctionReflection;
7+
use PHPStan\Reflection\FunctionVariantWithPhpDocs;
8+
use PHPStan\Reflection\ParametersAcceptorWithPhpDocs;
9+
use PHPStan\Reflection\PassedByReference;
10+
use PHPStan\TrinaryLogic;
11+
use PHPStan\Type\Constant\ConstantIntegerType;
12+
use PHPStan\Type\Generic\TemplateTypeMap;
13+
use PHPStan\Type\Generic\TemplateTypeVarianceMap;
14+
use PHPStan\Type\IntegerType;
15+
use PHPStan\Type\MixedType;
16+
use PHPStan\Type\NeverType;
17+
use PHPStan\Type\StringType;
18+
use PHPStan\Type\Type;
19+
use PHPStan\Type\UnionType;
20+
21+
final class ExitFunctionReflection implements FunctionReflection
22+
{
23+
24+
public function __construct(private string $name)
25+
{
26+
}
27+
28+
public function getName(): string
29+
{
30+
return $this->name;
31+
}
32+
33+
public function getFileName(): ?string
34+
{
35+
return null;
36+
}
37+
38+
public function getVariants(): array
39+
{
40+
$parameterType = new UnionType([
41+
new StringType(),
42+
new IntegerType(),
43+
]);
44+
return [
45+
new FunctionVariantWithPhpDocs(
46+
TemplateTypeMap::createEmpty(),
47+
TemplateTypeMap::createEmpty(),
48+
[
49+
new DummyParameterWithPhpDocs(
50+
'status',
51+
$parameterType,
52+
true,
53+
PassedByReference::createNo(),
54+
false,
55+
new ConstantIntegerType(0),
56+
$parameterType,
57+
new MixedType(),
58+
null,
59+
TrinaryLogic::createNo(),
60+
null,
61+
),
62+
],
63+
false,
64+
new NeverType(true),
65+
new MixedType(),
66+
new NeverType(true),
67+
TemplateTypeVarianceMap::createEmpty(),
68+
),
69+
];
70+
}
71+
72+
/**
73+
* @return ParametersAcceptorWithPhpDocs[]
74+
*/
75+
public function getNamedArgumentsVariants(): array
76+
{
77+
return $this->getVariants();
78+
}
79+
80+
public function acceptsNamedArguments(): bool
81+
{
82+
return true;
83+
}
84+
85+
public function isDeprecated(): TrinaryLogic
86+
{
87+
return TrinaryLogic::createNo();
88+
}
89+
90+
public function getDeprecatedDescription(): ?string
91+
{
92+
return null;
93+
}
94+
95+
public function isFinal(): TrinaryLogic
96+
{
97+
return TrinaryLogic::createNo();
98+
}
99+
100+
public function isInternal(): TrinaryLogic
101+
{
102+
return TrinaryLogic::createYes();
103+
}
104+
105+
public function getThrowType(): ?Type
106+
{
107+
return null;
108+
}
109+
110+
public function hasSideEffects(): TrinaryLogic
111+
{
112+
return TrinaryLogic::createYes();
113+
}
114+
115+
public function isBuiltin(): bool
116+
{
117+
return true;
118+
}
119+
120+
public function getAsserts(): Assertions
121+
{
122+
return Assertions::createEmpty();
123+
}
124+
125+
public function getDocComment(): ?string
126+
{
127+
return null;
128+
}
129+
130+
public function returnsByReference(): TrinaryLogic
131+
{
132+
return TrinaryLogic::createNo();
133+
}
134+
135+
public function isPure(): TrinaryLogic
136+
{
137+
return TrinaryLogic::createNo();
138+
}
139+
140+
}

0 commit comments

Comments
 (0)