diff --git a/ext/standard/array.c b/ext/standard/array.c index f8dd7d891dd3..edacfb644e2e 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -6494,42 +6494,71 @@ PHP_FUNCTION(array_filter) } } - ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) { - if (have_callback) { - if (use_type != ARRAY_FILTER_USE_VALUE) { - /* Set up the key */ - if (!string_key) { + if (HT_IS_PACKED(Z_ARRVAL_P(array))) { + ZEND_HASH_PACKED_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, operand) { + if (have_callback) { + if (use_type != ARRAY_FILTER_USE_VALUE) { ZVAL_LONG(key, num_key); - } else { - ZVAL_STR(key, string_key); } - } - if (use_type != ARRAY_FILTER_USE_KEY) { - ZVAL_COPY_VALUE(&args[0], operand); - } - fci.params = args; + if (use_type != ARRAY_FILTER_USE_KEY) { + ZVAL_COPY_VALUE(&args[0], operand); + } + fci.params = args; - zend_result result = zend_call_function(&fci, &fci_cache); - ZEND_ASSERT(result == SUCCESS); + zend_result result = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(result == SUCCESS); - if (UNEXPECTED(EG(exception))) { - RETURN_THROWS(); - } + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } - if (!php_is_true(&retval)) { + if (!php_is_true(&retval)) { + continue; + } + } else if (!zend_is_true(operand)) { continue; } - } else if (!zend_is_true(operand)) { - continue; - } - if (string_key) { - operand = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, operand); - } else { operand = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, operand); - } - zval_add_ref(operand); - } ZEND_HASH_FOREACH_END(); + zval_add_ref(operand); + } ZEND_HASH_FOREACH_END(); + } else { + ZEND_HASH_MAP_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_key, string_key, operand) { + if (have_callback) { + if (use_type != ARRAY_FILTER_USE_VALUE) { + if (!string_key) { + ZVAL_LONG(key, num_key); + } else { + ZVAL_STR(key, string_key); + } + } + if (use_type != ARRAY_FILTER_USE_KEY) { + ZVAL_COPY_VALUE(&args[0], operand); + } + fci.params = args; + + zend_result result = zend_call_function(&fci, &fci_cache); + ZEND_ASSERT(result == SUCCESS); + + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } + + if (!php_is_true(&retval)) { + continue; + } + } else if (!zend_is_true(operand)) { + continue; + } + + if (string_key) { + operand = zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, operand); + } else { + operand = zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, operand); + } + zval_add_ref(operand); + } ZEND_HASH_FOREACH_END(); + } } /* }}} */ diff --git a/ext/standard/tests/array/array_filter.phpt b/ext/standard/tests/array/array_filter/array_filter.phpt similarity index 100% rename from ext/standard/tests/array/array_filter.phpt rename to ext/standard/tests/array/array_filter/array_filter.phpt diff --git a/ext/standard/tests/array/array_filter_basic.phpt b/ext/standard/tests/array/array_filter/array_filter_basic.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_basic.phpt rename to ext/standard/tests/array/array_filter/array_filter_basic.phpt diff --git a/ext/standard/tests/array/array_filter_invalid_mode.phpt b/ext/standard/tests/array/array_filter/array_filter_invalid_mode.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_invalid_mode.phpt rename to ext/standard/tests/array/array_filter/array_filter_invalid_mode.phpt diff --git a/ext/standard/tests/array/array_filter_object.phpt b/ext/standard/tests/array/array_filter/array_filter_object.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_object.phpt rename to ext/standard/tests/array/array_filter/array_filter_object.phpt diff --git a/ext/standard/tests/array/array_filter/array_filter_packed.phpt b/ext/standard/tests/array/array_filter/array_filter_packed.phpt new file mode 100644 index 000000000000..d387f9c086e8 --- /dev/null +++ b/ext/standard/tests/array/array_filter/array_filter_packed.phpt @@ -0,0 +1,140 @@ +--TEST-- +Test array_filter() function : packed array handling with different modes +--FILE-- + 2; +}, ARRAY_FILTER_USE_KEY)); + +echo "-- ARRAY_FILTER_USE_BOTH with packed array --\n"; +var_dump(array_filter($packed, function($value, $key) { + return $key > 0 && $value > 20; +}, ARRAY_FILTER_USE_BOTH)); + +echo "-- ARRAY_FILTER_USE_KEY with packed array (no matches) --\n"; +var_dump(array_filter($packed, function($key) { + return $key > 100; +}, ARRAY_FILTER_USE_KEY)); + +echo "-- ARRAY_FILTER_USE_BOTH with packed array (all match) --\n"; +var_dump(array_filter($packed, function($value, $key) { + return is_int($key) && is_int($value); +}, ARRAY_FILTER_USE_BOTH)); + +echo "-- ARRAY_FILTER_USE_KEY verifying keys are integers --\n"; +$types = []; +array_filter($packed, function($key) use (&$types) { + $types[] = get_debug_type($key); + return true; +}, ARRAY_FILTER_USE_KEY); +var_dump($types); + +echo "-- ARRAY_FILTER_USE_BOTH verifying keys are integers --\n"; +$types = []; +array_filter($packed, function($value, $key) use (&$types) { + $types[] = get_debug_type($key); + return true; +}, ARRAY_FILTER_USE_BOTH); +var_dump($types); + +echo "-- Packed array with gaps --\n"; +$gapped = [10, 20, 30, 40, 50]; +unset($gapped[2]); +var_dump(array_filter($gapped, function($key) { + return $key >= 2; +}, ARRAY_FILTER_USE_KEY)); + +var_dump(array_filter($gapped, function($value, $key) { + return $key >= 2 && $value > 30; +}, ARRAY_FILTER_USE_BOTH)); + +echo "-- No callback with packed array --\n"; +$mixed_values = [0, 1, "", "hello", null, true, false, 42]; +var_dump(array_filter($mixed_values)); + +?> +--EXPECT-- +-- ARRAY_FILTER_USE_KEY with packed array -- +array(2) { + [3]=> + int(40) + [4]=> + int(50) +} +-- ARRAY_FILTER_USE_BOTH with packed array -- +array(3) { + [2]=> + int(30) + [3]=> + int(40) + [4]=> + int(50) +} +-- ARRAY_FILTER_USE_KEY with packed array (no matches) -- +array(0) { +} +-- ARRAY_FILTER_USE_BOTH with packed array (all match) -- +array(5) { + [0]=> + int(10) + [1]=> + int(20) + [2]=> + int(30) + [3]=> + int(40) + [4]=> + int(50) +} +-- ARRAY_FILTER_USE_KEY verifying keys are integers -- +array(5) { + [0]=> + string(3) "int" + [1]=> + string(3) "int" + [2]=> + string(3) "int" + [3]=> + string(3) "int" + [4]=> + string(3) "int" +} +-- ARRAY_FILTER_USE_BOTH verifying keys are integers -- +array(5) { + [0]=> + string(3) "int" + [1]=> + string(3) "int" + [2]=> + string(3) "int" + [3]=> + string(3) "int" + [4]=> + string(3) "int" +} +-- Packed array with gaps -- +array(2) { + [3]=> + int(40) + [4]=> + int(50) +} +array(2) { + [3]=> + int(40) + [4]=> + int(50) +} +-- No callback with packed array -- +array(4) { + [1]=> + int(1) + [3]=> + string(5) "hello" + [5]=> + bool(true) + [7]=> + int(42) +} diff --git a/ext/standard/tests/array/array_filter_variation10.phpt b/ext/standard/tests/array/array_filter/array_filter_variation10.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation10.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation10.phpt diff --git a/ext/standard/tests/array/array_filter_variation3.phpt b/ext/standard/tests/array/array_filter/array_filter_variation3.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation3.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation3.phpt diff --git a/ext/standard/tests/array/array_filter_variation4.phpt b/ext/standard/tests/array/array_filter/array_filter_variation4.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation4.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation4.phpt diff --git a/ext/standard/tests/array/array_filter_variation5.phpt b/ext/standard/tests/array/array_filter/array_filter_variation5.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation5.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation5.phpt diff --git a/ext/standard/tests/array/array_filter_variation6.phpt b/ext/standard/tests/array/array_filter/array_filter_variation6.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation6.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation6.phpt diff --git a/ext/standard/tests/array/array_filter_variation7.phpt b/ext/standard/tests/array/array_filter/array_filter_variation7.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation7.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation7.phpt diff --git a/ext/standard/tests/array/array_filter_variation8.phpt b/ext/standard/tests/array/array_filter/array_filter_variation8.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation8.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation8.phpt diff --git a/ext/standard/tests/array/array_filter_variation9.phpt b/ext/standard/tests/array/array_filter/array_filter_variation9.phpt similarity index 100% rename from ext/standard/tests/array/array_filter_variation9.phpt rename to ext/standard/tests/array/array_filter/array_filter_variation9.phpt