Skip to content

Commit 7e3185f

Browse files
committed
Implement SocketCreateReturnTypeExtension
1 parent 72b31c0 commit 7e3185f

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,11 @@ services:
18291829
tags:
18301830
- phpstan.broker.dynamicMethodReturnTypeExtension
18311831

1832+
-
1833+
class: PHPStan\Type\Php\SocketCreateReturnTypeExtension
1834+
tags:
1835+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1836+
18321837
-
18331838
class: PHPStan\Type\Php\StrSplitFunctionReturnTypeExtension
18341839
tags:

src/Php/PhpVersions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public function producesWarningForFinalPrivateMethods(): TrinaryLogic
3333
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
3434
}
3535

36+
public function socketCreateUsesResource(): TrinaryLogic
37+
{
38+
return IntegerRangeType::fromInterval(null, 80000)->isSuperTypeOf($this->phpVersions)->result;
39+
}
40+
3641
public function supportsNamedArguments(): TrinaryLogic
3742
{
3843
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\FunctionReflection;
8+
use PHPStan\Type\Constant\ConstantBooleanType;
9+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
10+
use PHPStan\Type\ObjectType;
11+
use PHPStan\Type\ResourceType;
12+
use PHPStan\Type\Type;
13+
use PHPStan\Type\UnionType;
14+
use Socket;
15+
use function count;
16+
17+
final class SocketCreateReturnTypeExtension implements DynamicFunctionReturnTypeExtension
18+
{
19+
20+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
21+
{
22+
return $functionReflection->getName() === 'socket_create';
23+
}
24+
25+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
26+
{
27+
if (count($functionCall->getArgs()) < 3) {
28+
return null;
29+
}
30+
31+
if ($scope->getPhpVersion()->socketCreateUsesResource()->no()) {
32+
return new UnionType([new ConstantBooleanType(false), new ObjectType(Socket::class)]);
33+
}
34+
35+
if ($scope->getPhpVersion()->socketCreateUsesResource()->yes()) {
36+
return new UnionType([new ConstantBooleanType(false), new ResourceType()]);
37+
}
38+
39+
return null;
40+
}
41+
42+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php // lint >= 7.4
2+
3+
declare(strict_types=1);
4+
5+
namespace SocketCreate;
6+
7+
use function PHPStan\Testing\assertType;
8+
9+
class HelloWorld
10+
{
11+
public function sayHello(): void
12+
{
13+
if (PHP_VERSION_ID < 80000) {
14+
assertType('resource|false', socket_create(AF_INET, SOCK_DGRAM, SOL_UDP));
15+
return;
16+
}
17+
assertType('Socket|false', socket_create(AF_INET, SOCK_DGRAM, SOL_UDP));
18+
}
19+
}

0 commit comments

Comments
 (0)