diff --git a/ext/standard/array_search.php b/ext/standard/array_search.php
index 666ec8a3974..3e282987fb7 100644
--- a/ext/standard/array_search.php
+++ b/ext/standard/array_search.php
@@ -17,6 +17,7 @@
use PHPCompiler\JIT\Context;
use PHPCompiler\JIT\ExceptionBridge;
use PHPCompiler\JIT\JitBoolArg;
+use PHPCompiler\JIT\JitNativeString;
use PHPCompiler\JIT\JitValueBox;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPLLVM\Value;
@@ -40,9 +41,10 @@ public function execute(Frame $frame): void
2,
'haystack'
);
+ // Z_PARAM_BOOL $strict — strict_types TypeError; else null→false + E_DEPRECATED (#29866).
$strict = false;
if (3 === $argc) {
- $strict = $frame->calledArgs[2]->resolveIndirect()->toBool();
+ $strict = VmMath::parseBoolBuiltinArgForFrame($frame, 2, 'array_search', 3, 'strict');
}
$vm = null !== $frame->vmContext ? $frame->vmContext->runtime->vm() : null;
if (null === $frame->returnVar) {
@@ -70,7 +72,17 @@ public function call(Context $context, JITVariable ...$args): Value
}
$strict = $context->constantFromBool(false);
if (3 === $argc) {
- $strict = JitBoolArg::lower($context, $args[2], 'array_search() strict');
+ // Compile-time null under strict: catchable TypeError then stop IR (peer substr_compare #29756).
+ if ($context->callerStrictTypes && self::isCompileTimeNull($args[2])) {
+ JitNativeString::ensureInsertBlock($context);
+ ExceptionBridge::emitTypeErrorAndAbort(
+ $context,
+ 'array_search(): Argument #3 ($strict) must be of type bool, null given'
+ );
+
+ return $context->constantFromBool(false);
+ }
+ $strict = JitBoolArg::lowerCoerceZParamBool($context, $args[2], 'array_search', 'strict', 3);
}
if (JITVariable::TYPE_STRING === $args[0]->type || JITVariable::TYPE_VALUE === $args[0]->type) {
$this->jitString($context, $args[0], 'array_search() needle');
@@ -79,4 +91,9 @@ public function call(Context $context, JITVariable ...$args): Value
return ArraySearchRuntime::search($context, $args[0], $args[1], $strict);
}
+
+ private static function isCompileTimeNull(JITVariable $arg): bool
+ {
+ return JITVariable::TYPE_NULL === $arg->type || ($arg->isNullConstant ?? false);
+ }
}
diff --git a/ext/standard/in_array.php b/ext/standard/in_array.php
index 3abd4ac051c..e29f8336f9c 100644
--- a/ext/standard/in_array.php
+++ b/ext/standard/in_array.php
@@ -15,13 +15,17 @@
use PHPCompiler\Func\Internal;
use PHPCompiler\JIT\Builtin\InArrayRuntime;
use PHPCompiler\JIT\Context;
+use PHPCompiler\JIT\ExceptionBridge;
use PHPCompiler\JIT\JitBoolArg;
+use PHPCompiler\JIT\JitNativeString;
use PHPCompiler\JIT\Variable as JITVariable;
use PHPCompiler\VM\Variable;
use PHPLLVM\Value;
/**
* in_array() for arrays of scalar values (subset of PHP; JIT via InArrayRuntime).
+ *
+ * php-src: ext/standard/array.stub.php / array.c — PHP_FUNCTION(in_array)
*/
final class in_array extends Internal
{
@@ -48,9 +52,10 @@ public function execute(Frame $frame): void
2,
'haystack'
);
+ // Z_PARAM_BOOL $strict — strict_types TypeError; else null→false + E_DEPRECATED (#29866).
$strict = false;
- if (3 === \count($frame->calledArgs)) {
- $strict = $frame->calledArgs[2]->resolveIndirect()->toBool();
+ if (3 === $argc) {
+ $strict = VmMath::parseBoolBuiltinArgForFrame($frame, 2, 'in_array', 3, 'strict');
}
if (null === $frame->returnVar) {
return;
@@ -81,8 +86,18 @@ public function call(Context $context, JITVariable ...$args): Value
));
}
$strict = $context->constantFromBool(false);
- if (3 === \count($args)) {
- $strict = JitBoolArg::lower($context, $args[2], 'in_array() strict');
+ if (3 === $argc) {
+ // Compile-time null under strict: catchable TypeError then stop IR (peer substr_compare #29756).
+ if ($context->callerStrictTypes && self::isCompileTimeNull($args[2])) {
+ JitNativeString::ensureInsertBlock($context);
+ ExceptionBridge::emitTypeErrorAndAbort(
+ $context,
+ 'in_array(): Argument #3 ($strict) must be of type bool, null given'
+ );
+
+ return $context->constantFromBool(false);
+ }
+ $strict = JitBoolArg::lowerCoerceZParamBool($context, $args[2], 'in_array', 'strict', 3);
}
if (JITVariable::TYPE_STRING === $args[0]->type || JITVariable::TYPE_VALUE === $args[0]->type) {
$this->jitString($context, $args[0], 'in_array() needle');
@@ -97,4 +112,9 @@ public function call(Context $context, JITVariable ...$args): Value
return InArrayRuntime::inArray($context, $args[0], $args[1], $strict);
}
+
+ private static function isCompileTimeNull(JITVariable $arg): bool
+ {
+ return JITVariable::TYPE_NULL === $arg->type || ($arg->isNullConstant ?? false);
+ }
}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 522d1dcb7d3..d0fe9abc476 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -288,6 +288,8 @@
./test/compliance/SubstrCompareNullCiCoerceJITTest.php
./test/compliance/Base64DecodeStrictNullVMTest.php
./test/compliance/Base64DecodeStrictNullJITTest.php
+ ./test/compliance/InArrayArraySearchStrictNullVMTest.php
+ ./test/compliance/InArrayArraySearchStrictNullJITTest.php
./test/compliance/SubstrReplaceNullReplaceStrictVMTest.php
./test/compliance/SubstrReplaceNullReplaceStrictJITTest.php
./test/compliance/MetaphoneMaxPhonemesValueErrorVMTest.php
diff --git a/test/compliance/InArrayArraySearchStrictNullJITTest.php b/test/compliance/InArrayArraySearchStrictNullJITTest.php
new file mode 100644
index 00000000000..b8f308bcb49
--- /dev/null
+++ b/test/compliance/InArrayArraySearchStrictNullJITTest.php
@@ -0,0 +1,29 @@
+ self::parsePHPT(
+ __DIR__.'/cases/stdlib/in_array_array_search_strict_null_jit.phpt',
+ 'in_array_array_search_strict_null_jit.phpt'
+ );
+ }
+
+ public function setUp(): void
+ {
+ $this->BIN = realpath(__DIR__.'/../../bin/jit.php');
+ }
+}
diff --git a/test/compliance/InArrayArraySearchStrictNullVMTest.php b/test/compliance/InArrayArraySearchStrictNullVMTest.php
new file mode 100644
index 00000000000..60988ee761f
--- /dev/null
+++ b/test/compliance/InArrayArraySearchStrictNullVMTest.php
@@ -0,0 +1,30 @@
+ self::parsePHPT(
+ __DIR__.'/cases/stdlib/in_array_array_search_strict_null.phpt',
+ 'in_array_array_search_strict_null.phpt'
+ );
+ yield 'in_array_array_search_strict_null_weak.phpt' => self::parsePHPT(
+ __DIR__.'/cases/stdlib/in_array_array_search_strict_null_weak.phpt',
+ 'in_array_array_search_strict_null_weak.phpt'
+ );
+ }
+
+ public function setUp(): void
+ {
+ $this->BIN = realpath(__DIR__.'/../../bin/vm.php');
+ }
+}
diff --git a/test/compliance/cases/stdlib/in_array_array_search_strict_null.phpt b/test/compliance/cases/stdlib/in_array_array_search_strict_null.phpt
new file mode 100644
index 00000000000..7c966d4fe38
--- /dev/null
+++ b/test/compliance/cases/stdlib/in_array_array_search_strict_null.phpt
@@ -0,0 +1,29 @@
+--TEST--
+stdlib in_array/array_search(null $strict) under strict_types TypeError (#29866, ext/standard/array.c Z_PARAM_BOOL)
+--FILE--
+getMessage(), "\n";
+}
+try {
+ var_export(array_search(1, [1], null));
+ echo " uncaught\n";
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+$s = null;
+try {
+ var_export(in_array(1, [1], $s));
+ echo " uncaught-var\n";
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+--EXPECT--
+in_array(): Argument #3 ($strict) must be of type bool, null given
+array_search(): Argument #3 ($strict) must be of type bool, null given
+in_array(): Argument #3 ($strict) must be of type bool, null given
diff --git a/test/compliance/cases/stdlib/in_array_array_search_strict_null_jit.phpt b/test/compliance/cases/stdlib/in_array_array_search_strict_null_jit.phpt
new file mode 100644
index 00000000000..7210bceabcd
--- /dev/null
+++ b/test/compliance/cases/stdlib/in_array_array_search_strict_null_jit.phpt
@@ -0,0 +1,21 @@
+--TEST--
+JIT: in_array/array_search(null $strict) under strict_types TypeError (#29866, ext/standard/array.c Z_PARAM_BOOL)
+--FILE--
+getMessage(), "\n";
+}
+try {
+ var_export(array_search(1, [1], null));
+ echo " uncaught\n";
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+--EXPECT--
+in_array(): Argument #3 ($strict) must be of type bool, null given
+array_search(): Argument #3 ($strict) must be of type bool, null given
diff --git a/test/compliance/cases/stdlib/in_array_array_search_strict_null_weak.phpt b/test/compliance/cases/stdlib/in_array_array_search_strict_null_weak.phpt
new file mode 100644
index 00000000000..426cdea7f71
--- /dev/null
+++ b/test/compliance/cases/stdlib/in_array_array_search_strict_null_weak.phpt
@@ -0,0 +1,23 @@
+--TEST--
+stdlib in_array/array_search(null $strict) without strict_types — Deprecated + coerce (#29866, ext/standard/array.c)
+--FILE--
+getMessage(), "\n";
+}
+try {
+ var_export(array_search(1, [1], null));
+ echo "\n";
+} catch (TypeError $e) {
+ echo $e->getMessage(), "\n";
+}
+?>
+--EXPECT--
+in_array(): Argument #3 ($strict) must be of type bool, null given
+array_search(): Argument #3 ($strict) must be of type bool, null given
diff --git a/test/repro/issue_29866_in_array_strict_null.php b/test/repro/issue_29866_in_array_strict_null.php
new file mode 100644
index 00000000000..dbad7b71fa4
--- /dev/null
+++ b/test/repro/issue_29866_in_array_strict_null.php
@@ -0,0 +1,15 @@
+getMessage(), "\n";
+}
+try {
+ var_export(array_search(1, [1], null));
+ echo "\n";
+} catch (Throwable $e) {
+ echo get_class($e), ': ', $e->getMessage(), "\n";
+}