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)