From 9b5349b1d40763f79694ccfd41c1d88c2e3f4660 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Sat, 29 Nov 2025 15:46:35 +0100 Subject: [PATCH 1/2] Fix "Array does not have offset" in curl_setopt_array() --- src/Reflection/ParametersAcceptorSelector.php | 5 +- .../CallToFunctionParametersRuleTest.php | 12 ++++ .../Rules/Functions/data/bug-13862.php | 66 +++++++++++++++++++ .../Rules/Functions/data/bug-13862b.php | 12 ++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 tests/PHPStan/Rules/Functions/data/bug-13862.php create mode 100644 tests/PHPStan/Rules/Functions/data/bug-13862b.php diff --git a/src/Reflection/ParametersAcceptorSelector.php b/src/Reflection/ParametersAcceptorSelector.php index 04f4917b45..353bafc7e0 100644 --- a/src/Reflection/ParametersAcceptorSelector.php +++ b/src/Reflection/ParametersAcceptorSelector.php @@ -181,7 +181,9 @@ public static function selectFromArgs( $hasTypes = false; $builder = ConstantArrayTypeBuilder::createEmpty(); - foreach ($optArrayType->getIterableKeyType()->getConstantScalarValues() as $optValue) { + foreach ($optArrayType->getIterableKeyType()->getConstantScalarTypes() as $optType) { + $optValue = $optType->getValue(); + if (!is_int($optValue)) { $hasTypes = false; break; @@ -197,6 +199,7 @@ public static function selectFromArgs( $builder->setOffsetValueType( new ConstantIntegerType($optValue), $optValueType, + !$optArrayType->hasOffsetValueType($optType)->yes(), ); } diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 5f4bb1bf7c..910212d519 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -2476,4 +2476,16 @@ public function testClone(): void ]); } + #[RequiresPhp('>= 8.1')] + public function testBug13862(): void + { + $this->analyse([__DIR__ . '/data/bug-13862.php'], []); + } + + #[RequiresPhp('>= 8.1')] + public function testBug13862b(): void + { + $this->analyse([__DIR__ . '/data/bug-13862b.php'], []); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/bug-13862.php b/tests/PHPStan/Rules/Functions/data/bug-13862.php new file mode 100644 index 0000000000..d935c2fa36 --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-13862.php @@ -0,0 +1,66 @@ + $url, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_TIMEOUT => 15, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_PORT => 443, + CURLOPT_ENCODING => "gzip, deflate", + CURLOPT_HTTPHEADER => array("Accept-Encoding: gzip, deflate") + ); + + if ($curl_interface != "") + $options[CURLOPT_INTERFACE] = $curl_interface; + + if ($port !== null) + $options[CURLOPT_PORT] = $port; + + if ($post !== null) { + $options[CURLOPT_POST] = true; + $options[CURLOPT_POSTFIELDS] = $post; + $options[CURLOPT_HTTPHEADER] = array( + "Content-Type: application/json;charset=\"UTF-8\"", + "Accept: application/json", + "Accept-Encoding: gzip, deflate", + "Content-Length: " . mb_strlen($post, "UTF-8") + ); + } + + $curl = curl_init(); + curl_setopt_array($curl, $options); + $rc = curl_exec($curl); + if (is_bool($rc)) + return ""; + else + return $rc; + + } + +} + +$foo = new foo(); +$data = $foo->getUrl("https://example.tld"); diff --git a/tests/PHPStan/Rules/Functions/data/bug-13862b.php b/tests/PHPStan/Rules/Functions/data/bug-13862b.php new file mode 100644 index 0000000000..daaaa4a5de --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-13862b.php @@ -0,0 +1,12 @@ + Date: Sat, 29 Nov 2025 15:50:33 +0100 Subject: [PATCH 2/2] assert errors on optional but wrong value types --- .../Functions/CallToFunctionParametersRuleTest.php | 12 ++++++++++++ tests/PHPStan/Rules/Functions/data/bug-13862c.php | 12 ++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/PHPStan/Rules/Functions/data/bug-13862c.php diff --git a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php index 910212d519..895150be05 100644 --- a/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php +++ b/tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php @@ -2488,4 +2488,16 @@ public function testBug13862b(): void $this->analyse([__DIR__ . '/data/bug-13862b.php'], []); } + #[RequiresPhp('>= 8.1')] + public function testBug13862c(): void + { + $this->analyse([__DIR__ . '/data/bug-13862c.php'], [ + [ + 'Parameter #2 $options of function curl_setopt_array expects array{10022?: non-empty-string}, array{}|array{10022: 123} given.', + 12, + 'Offset 10022 (non-empty-string) does not accept type 123.', + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Functions/data/bug-13862c.php b/tests/PHPStan/Rules/Functions/data/bug-13862c.php new file mode 100644 index 0000000000..1b8ed7511d --- /dev/null +++ b/tests/PHPStan/Rules/Functions/data/bug-13862c.php @@ -0,0 +1,12 @@ +