Skip to content

Commit 13eaee7

Browse files
committed
Implement php-version dependent socket_* return type handling
1 parent 72b31c0 commit 13eaee7

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed

conf/config.neon

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

1832+
-
1833+
class: PHPStan\Type\Php\SocketObjectReturnTypeFunctionExtension
1834+
tags:
1835+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1836+
1837+
-
1838+
class: PHPStan\Type\Php\AddressInfoObjectReturnTypeFunctionExtension
1839+
tags:
1840+
- phpstan.broker.dynamicFunctionReturnTypeExtension
1841+
18321842
-
18331843
class: PHPStan\Type\Php\StrSplitFunctionReturnTypeExtension
18341844
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 socketFunctionsUseObject(): TrinaryLogic
37+
{
38+
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
39+
}
40+
3641
public function supportsNamedArguments(): TrinaryLogic
3742
{
3843
return IntegerRangeType::fromInterval(80000, null)->isSuperTypeOf($this->phpVersions)->result;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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\ArrayType;
9+
use PHPStan\Type\Constant\ConstantBooleanType;
10+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
11+
use PHPStan\Type\MixedType;
12+
use PHPStan\Type\ObjectType;
13+
use PHPStan\Type\ResourceType;
14+
use PHPStan\Type\Type;
15+
use PHPStan\Type\UnionType;
16+
use function in_array;
17+
18+
final class AddressInfoObjectReturnTypeFunctionExtension implements DynamicFunctionReturnTypeExtension
19+
{
20+
21+
private const FUNCTIONS = [
22+
'socket_addrinfo_lookup',
23+
];
24+
25+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
26+
{
27+
return in_array($functionReflection->getName(), self::FUNCTIONS, true);
28+
}
29+
30+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
31+
{
32+
if ($scope->getPhpVersion()->socketFunctionsUseObject()->yes()) {
33+
return new UnionType([new ConstantBooleanType(false), new ArrayType(new MixedType(), new ObjectType('\\AddressInfo'))]);
34+
}
35+
36+
if ($scope->getPhpVersion()->socketFunctionsUseObject()->no()) {
37+
return new UnionType([new ConstantBooleanType(false), new ArrayType(new MixedType(), new ResourceType())]);
38+
}
39+
40+
return null;
41+
}
42+
43+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 function in_array;
15+
16+
final class SocketObjectReturnTypeFunctionExtension implements DynamicFunctionReturnTypeExtension
17+
{
18+
19+
private const FUNCTIONS = [
20+
'socket_accept',
21+
'socket_addrinfo_bind',
22+
'socket_addrinfo_connect',
23+
'socket_create',
24+
'socket_create_listen',
25+
'socket_import_stream',
26+
'socket_wsaprotocol_info_import',
27+
];
28+
29+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
30+
{
31+
return in_array($functionReflection->getName(), self::FUNCTIONS, true);
32+
}
33+
34+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): ?Type
35+
{
36+
if ($scope->getPhpVersion()->socketFunctionsUseObject()->yes()) {
37+
return new UnionType([new ConstantBooleanType(false), new ObjectType('\\Socket')]);
38+
}
39+
40+
if ($scope->getPhpVersion()->socketFunctionsUseObject()->no()) {
41+
return new UnionType([new ConstantBooleanType(false), new ResourceType()]);
42+
}
43+
44+
return null;
45+
}
46+
47+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 createSocket(): void
12+
{
13+
if (PHP_VERSION_ID < 80000) {
14+
assertType('resource|false', socket_create(AF_INET, SOCK_DGRAM, SOL_UDP));
15+
}
16+
17+
if (PHP_VERSION_ID >= 80000) {
18+
assertType('\Socket|false', socket_create(AF_INET, SOCK_DGRAM, SOL_UDP));
19+
}
20+
}
21+
22+
public function addrinfo($host): void
23+
{
24+
if (PHP_VERSION_ID < 80000) {
25+
assertType('array<resource>|false', socket_addrinfo_lookup($host));
26+
}
27+
28+
if (PHP_VERSION_ID >= 80000) {
29+
assertType('array<\AddressInfo>|false', socket_addrinfo_lookup($host));
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)