Commit 43f610cc550 for php

commit 43f610cc5504a39ca4ba41e1297daceb613449b9
Author: Alexander Danilov <10532067+adapik@users.noreply.github.com>
Date:   Mon Nov 9 14:09:44 2026 +0200

    ext/standard: Speed up strict in_array()/array_search() with a string needle (#25280)

diff --git a/NEWS b/NEWS
index 81a3b5ebd55..5a865955281 100644
--- a/NEWS
+++ b/NEWS
@@ -193,6 +193,8 @@ PHP                                                                        NEWS
   . bindec(), octdec(), hexdec() and base_convert() now throw an Exception
     when the passed string contains characters that are invalid for the
     specified number base. (Sjoerd Langkemper)
+  . Improved performance of in_array() and array_search() in strict mode when
+    searching for a string. (Alexander Danilov)

 - URI:
   . Fix casing of enum cases in UriHostType and UrlHostType to match the RFC
diff --git a/UPGRADING b/UPGRADING
index 3867497fa9c..a4df2335263 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -206,6 +206,8 @@ PHP 8.7 UPGRADE NOTES
     UTF-8.
   . htmlspecialchars() returns its input without copying it when nothing needs
     encoding.
+  . Improved performance of in_array() and array_search() in strict mode when
+    searching for a string.

 - MBString:
   . Improved performance of mb_strlen for UTF-8 strings.
diff --git a/ext/standard/array.c b/ext/standard/array.c
index b4ebd807321..fe5d7cfd55e 100644
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@ -1601,6 +1601,22 @@ static zend_always_inline void _php_search_array(zval *return_value, zval *value
 					}
 				}
 			} ZEND_HASH_FOREACH_END();
+		} else if (Z_TYPE_P(value) == IS_STRING) {
+			zend_string *needle = Z_STR_P(value);
+			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
+				ZVAL_DEREF(entry);
+				if (Z_TYPE_P(entry) == IS_STRING && zend_string_equals(Z_STR_P(entry), needle)) {
+					if (behavior == 0) {
+						RETURN_TRUE;
+					} else {
+						if (str_idx) {
+							RETURN_STR_COPY(str_idx);
+						} else {
+							RETURN_LONG(num_idx);
+						}
+					}
+				}
+			} ZEND_HASH_FOREACH_END();
 		} else {
 			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
 				ZVAL_DEREF(entry);
diff --git a/ext/standard/tests/array/in_array_array_search_strict_string.phpt b/ext/standard/tests/array/in_array_array_search_strict_string.phpt
new file mode 100644
index 00000000000..fcf4903f740
--- /dev/null
+++ b/ext/standard/tests/array/in_array_array_search_strict_string.phpt
@@ -0,0 +1,89 @@
+--TEST--
+in_array()/array_search() strict mode with a string needle
+--FILE--
+<?php
+
+function dyn(string $s): string { return $s . ''; }
+
+echo "-- found / not found --\n";
+$list = ['alpha', 'beta', '', "a\0b", 'kappa'];
+var_dump(in_array('kappa', $list, true));
+var_dump(in_array('nope', $list, true));
+var_dump(in_array('', $list, true));
+var_dump(in_array("a\0b", $list, true));
+var_dump(in_array("a\0c", $list, true));
+var_dump(in_array('alph', $list, true));
+var_dump(array_search('beta', $list, true));
+var_dump(array_search('nope', $list, true));
+
+echo "-- non-interned strings --\n";
+var_dump(in_array(dyn('beta'), $list, true));
+var_dump(in_array('beta', [dyn('beta')], true));
+var_dump(array_search(dyn('kappa'), [dyn('kappa')], true));
+
+echo "-- string and integer keys --\n";
+var_dump(array_search('b', ['x' => 'a', 'y' => 'b', 7 => 'c'], true));
+var_dump(array_search('c', ['x' => 'a', 'y' => 'b', 7 => 'c'], true));
+
+echo "-- elements of other types never match --\n";
+var_dump(in_array('1', [1, 1.0, true, [1], null], true));
+var_dump(in_array('', [null, false, 0, []], true));
+var_dump(in_array('abc', [0, true, new stdClass], true));
+var_dump(array_search('1', [1, '1'], true));
+
+echo "-- references --\n";
+$s = 'ref';
+$arr = [1, &$s, 3];
+var_dump(array_search('ref', $arr, true));
+$s = 'changed';
+var_dump(in_array('ref', $arr, true));
+var_dump(array_search('changed', $arr, true));
+$i = 5;
+var_dump(in_array('5', ['a', &$i], true));
+
+echo "-- holes --\n";
+$packed = ['a', 'b', 'c'];
+unset($packed[1]);
+var_dump(in_array('b', $packed, true));
+var_dump(array_search('c', $packed, true));
+$hash = ['x' => 'a', 'y' => 'b'];
+unset($hash['x']);
+var_dump(array_search('b', $hash, true));
+
+echo "-- empty array --\n";
+var_dump(in_array('a', [], true));
+
+?>
+--EXPECT--
+-- found / not found --
+bool(true)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+int(1)
+bool(false)
+-- non-interned strings --
+bool(true)
+bool(true)
+int(0)
+-- string and integer keys --
+string(1) "y"
+int(7)
+-- elements of other types never match --
+bool(false)
+bool(false)
+bool(false)
+int(1)
+-- references --
+int(1)
+bool(false)
+int(1)
+bool(false)
+-- holes --
+bool(false)
+int(2)
+string(1) "y"
+-- empty array --
+bool(false)