diff --git a/conf/config.neon b/conf/config.neon index c4724cb9e6..a1852419bf 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -436,6 +436,11 @@ services: tags: - phpstan.stubFilesExtension + - + class: PHPStan\PhpDoc\SocketSelectStubFilesExtension + tags: + - phpstan.stubFilesExtension + - class: PHPStan\PhpDoc\DefaultStubFilesProvider arguments: diff --git a/resources/functionMap.php b/resources/functionMap.php index b5f011f177..9fbd2a7ccd 100644 --- a/resources/functionMap.php +++ b/resources/functionMap.php @@ -10630,7 +10630,7 @@ 'socket_recv' => ['int|false', 'socket'=>'resource', '&w_buf'=>'string', 'len'=>'int', 'flags'=>'int'], 'socket_recvfrom' => ['int|false', 'socket'=>'resource', '&w_buf'=>'string', 'len'=>'int', 'flags'=>'int', '&w_name'=>'string', '&w_port='=>'int'], 'socket_recvmsg' => ['int|false', 'socket'=>'resource', '&w_message'=>'string', 'flags='=>'int'], -'socket_select' => ['int|false', '&rw_read_fds'=>'resource[]|null', '&rw_write_fds'=>'resource[]|null', '&rw_except_fds'=>'resource[]|null', 'tv_sec'=>'int|null', 'tv_usec='=>'int|null'], +'socket_select' => ['int|false', '&w_read_fds'=>'resource[]|null', '&w_write_fds'=>'resource[]|null', '&w_except_fds'=>'resource[]|null', 'tv_sec'=>'int|null', 'tv_usec='=>'int|null'], 'socket_send' => ['int|false', 'socket'=>'resource', 'buf'=>'string', 'len'=>'int', 'flags'=>'int'], 'socket_sendmsg' => ['int|false', 'socket'=>'resource', 'message'=>'array', 'flags'=>'int'], 'socket_sendto' => ['int|false', 'socket'=>'resource', 'buf'=>'string', 'len'=>'int', 'flags'=>'int', 'addr'=>'string', 'port='=>'int'], diff --git a/resources/functionMap_php80delta.php b/resources/functionMap_php80delta.php index fbe2debd4b..523d47eaef 100644 --- a/resources/functionMap_php80delta.php +++ b/resources/functionMap_php80delta.php @@ -95,7 +95,7 @@ 'proc_get_status' => ['array{command: string, pid: int, running: bool, signaled: bool, stopped: bool, exitcode: int, termsig: int, stopsig: int}', 'process'=>'resource'], 'set_error_handler' => ['?callable', 'callback'=>'null|callable(int,string,string,int):bool', 'error_types='=>'int'], 'socket_addrinfo_lookup' => ['AddressInfo[]', 'node'=>'string', 'service='=>'mixed', 'hints='=>'array'], - 'socket_select' => ['int|false', '&rw_read'=>'Socket[]|null', '&rw_write'=>'Socket[]|null', '&rw_except'=>'Socket[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], + 'socket_select' => ['int|false', '&w_read'=>'Socket[]|null', '&w_write'=>'Socket[]|null', '&w_except'=>'Socket[]|null', 'seconds'=>'int|null', 'microseconds='=>'int'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['string|false', 'confidential_message'=>'string', 'public_message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'str_contains' => ['bool', 'haystack'=>'string', 'needle'=>'string'], 'str_split' => ['non-empty-list', 'str'=>'string', 'split_length='=>'positive-int'], @@ -237,7 +237,7 @@ 'read_exif_data' => ['array', 'filename'=>'string', 'sections_needed='=>'string', 'sub_arrays='=>'bool', 'read_thumbnail='=>'bool'], 'restore_include_path' => ['void'], 'round' => ['__benevolent', 'number'=>'float', 'precision='=>'int', 'mode='=>'1|2|3|4'], - 'socket_select' => ['int|false', '&rw_read_fds'=>'resource[]|null', '&rw_write_fds'=>'resource[]|null', '&rw_except_fds'=>'resource[]|null', 'tv_sec'=>'int|null', 'tv_usec='=>'int|null'], + 'socket_select' => ['int|false', '&w_read_fds'=>'resource[]|null', '&w_write_fds'=>'resource[]|null', '&w_except_fds'=>'resource[]|null', 'tv_sec'=>'int|null', 'tv_usec='=>'int|null'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['?string|?false', 'confidential_message'=>'string', 'public_message'=>'string', 'nonce'=>'string', 'key'=>'string'], 'SplFileObject::fgetss' => ['string|false', 'allowable_tags='=>'string'], 'strchr' => ['string|false', 'haystack'=>'string', 'needle'=>'string|int', 'before_needle='=>'bool'], diff --git a/src/PhpDoc/SocketSelectStubFilesExtension.php b/src/PhpDoc/SocketSelectStubFilesExtension.php new file mode 100644 index 0000000000..1113a10f89 --- /dev/null +++ b/src/PhpDoc/SocketSelectStubFilesExtension.php @@ -0,0 +1,23 @@ +phpVersion->getVersionId() >= 80000) { + return [__DIR__ . '/../../stubs/socket_select_php8.stub']; + } + + return [__DIR__ . '/../../stubs/socket_select.stub']; + } + +} diff --git a/stubs/socket_select.stub b/stubs/socket_select.stub new file mode 100644 index 0000000000..3d4e9fe82f --- /dev/null +++ b/stubs/socket_select.stub @@ -0,0 +1,11 @@ +|null &$read + * @param array|null &$write + * @param array|null &$except + * @param-out ($read is not null ? array : null) $read + * @param-out ($write is not null ? array : null) $write + * @param-out ($except is not null ? array : null) $except + */ +function socket_select(?array &$read, ?array &$write, ?array &$except, ?int $seconds, int $microseconds = 0): int|false {} diff --git a/stubs/socket_select_php8.stub b/stubs/socket_select_php8.stub new file mode 100644 index 0000000000..f2a1704b42 --- /dev/null +++ b/stubs/socket_select_php8.stub @@ -0,0 +1,11 @@ +|null &$read + * @param array|null &$write + * @param array|null &$except + * @param-out ($read is not null ? array : null) $read + * @param-out ($write is not null ? array : null) $write + * @param-out ($except is not null ? array : null) $except + */ +function socket_select(?array &$read, ?array &$write, ?array &$except, ?int $seconds, int $microseconds = 0): int|false {} diff --git a/tests/PHPStan/Analyser/NodeScopeResolverTest.php b/tests/PHPStan/Analyser/NodeScopeResolverTest.php index 023f8dbe5d..ed61b2ceb2 100644 --- a/tests/PHPStan/Analyser/NodeScopeResolverTest.php +++ b/tests/PHPStan/Analyser/NodeScopeResolverTest.php @@ -255,6 +255,13 @@ public function dataFileAsserts(): iterable yield from $this->gatherAssertTypes(__DIR__ . '/data/generics-do-not-generalize.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9985.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6294.php'); + + if (PHP_VERSION_ID >= 80000) { + yield from $this->gatherAssertTypes(__DIR__ . '/data/discussion-10285-php8.php'); + } else { + yield from $this->gatherAssertTypes(__DIR__ . '/data/discussion-10285.php'); + } + yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-6462.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-2580.php'); yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-9753.php'); diff --git a/tests/PHPStan/Analyser/data/discussion-10285-php8.php b/tests/PHPStan/Analyser/data/discussion-10285-php8.php new file mode 100644 index 0000000000..67bf3afe8d --- /dev/null +++ b/tests/PHPStan/Analyser/data/discussion-10285-php8.php @@ -0,0 +1,21 @@ +', $read); + assertType('array', $write); + assertType('null', $except); + } +} diff --git a/tests/PHPStan/Analyser/data/discussion-10285.php b/tests/PHPStan/Analyser/data/discussion-10285.php new file mode 100644 index 0000000000..704cd94448 --- /dev/null +++ b/tests/PHPStan/Analyser/data/discussion-10285.php @@ -0,0 +1,21 @@ +', $read); + assertType('array', $write); + assertType('null', $except); + } +}