Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Zend/Optimizer/zend_func_infos.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ static const func_info_t func_infos[] = {
F1("ob_get_clean", MAY_BE_STRING|MAY_BE_FALSE),
F1("ob_list_handlers", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
F1("ob_get_status", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY),
FN("array_str_contains", MAY_BE_FALSE|MAY_BE_TRUE),
F1("compact", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
FN("array_fill", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY),
F1("array_fill_keys", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF),
Expand Down
50 changes: 50 additions & 0 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -7371,3 +7371,53 @@ PHP_FUNCTION(array_combine)
} ZEND_HASH_FOREACH_END();
}
/* }}} */
/* {{{ Filters array elements that contain a specific substring, preserving keys */
PHP_FUNCTION(array_str_contains)
{
HashTable *haystack;
zend_string *needle;
zval *val;
zend_string *key;
zend_ulong num_key;

ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_ARRAY_HT(haystack)
Z_PARAM_STR(needle)
ZEND_PARSE_PARAMETERS_END();

array_init(return_value);

if (zend_hash_num_elements(haystack) == 0) {
return;
}

/* Empty needle matches every string element */
bool needle_is_empty = (ZSTR_LEN(needle) == 0);

ZEND_HASH_FOREACH_KEY_VAL(haystack, num_key, key, val) {
ZVAL_DEREF(val);

if (Z_TYPE_P(val) != IS_STRING) {
continue;
}

bool match = false;
if (needle_is_empty) {
match = true;
} else if (Z_STRLEN_P(val) >= ZSTR_LEN(needle)) {
if (php_memnstr(Z_STRVAL_P(val), ZSTR_VAL(needle), ZSTR_LEN(needle), Z_STRVAL_P(val) + Z_STRLEN_P(val))) {
match = true;
}
}

if (match) {
Z_TRY_ADDREF_P(val);
if (key) {
zend_hash_add_new(Z_ARRVAL_P(return_value), key, val);
} else {
zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, val);
}
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */
5 changes: 5 additions & 0 deletions ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,11 @@ function array_walk_recursive(array|object &$array, callable $callback, mixed $a
* @frameless-function {"arity": 3}
*/
function in_array(mixed $needle, array $haystack, bool $strict = false): bool {}
/**
* @param array $haystack
* @return array
*/
function array_str_contains(array $haystack, string $needle): array {}

/**
* @compile-time-eval
Expand Down
9 changes: 8 additions & 1 deletion ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions ext/standard/basic_functions_decl.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions ext/standard/php_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@ ZEND_END_MODULE_GLOBALS(array)

#define ARRAYG(v) ZEND_MODULE_GLOBALS_ACCESSOR(array, v)

PHP_FUNCTION(array_str_contains);

#endif /* PHP_ARRAY_H */
37 changes: 37 additions & 0 deletions ext/standard/tests/array/array_str_contains.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
array_str_contains() basic functionality and edge cases
--FILE--
<?php

$fruits = ["apple", "banana", "cherry"];

// 1. Basic match
var_dump(array_str_contains($fruits, "apple"));
var_dump(array_str_contains($fruits, "banana"));
var_dump(array_str_contains($fruits, "cherry"));

// 2. No match
var_dump(array_str_contains($fruits, "orange"));
var_dump(array_str_contains($fruits, "app"));

// 3. Empty needle & empty array
var_dump(array_str_contains($fruits, ""));
var_dump(array_str_contains([], "apple"));
var_dump(array_str_contains([], ""));

// 4. Case-sensitivity
var_dump(array_str_contains($fruits, "APPLE"));
var_dump(array_str_contains($fruits, "Banana"));

?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(false)
bool(false)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
Loading