Skip to content

Commit 0212016

Browse files
committed
Make iterator_to_array() accept all iterables
While calling this function on an array either is a no-op or is equivalent to `\array_values()` if the `$preserve_keys` flag is `false`, it is also unnecessarily limiting for it to reject proper arrays. By allowing it to take the full `iterable` family, it is more easily possible to write a function that operates on an arbitrary `iterable` and internally uses array-specific functionality, such as `array_filter` or `array_map`: function test(iterable $foo) { $foo = iterator_to_array($foo); return array_map(strlen(...), $foo); } With this change it behaves similarly to `Array.from()` in JavaScript.
1 parent 782eefd commit 0212016

File tree

5 files changed

+61
-9
lines changed

5 files changed

+61
-9
lines changed

ext/spl/php_spl.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ function iterator_apply(Traversable $iterator, callable $callback, ?array $args
5151
function iterator_count(Traversable $iterator): int {}
5252

5353
/** @refcount 1 */
54-
function iterator_to_array(Traversable $iterator, bool $preserve_keys = true): array {}
54+
function iterator_to_array(iterable $iterator, bool $preserve_keys = true): array {}

ext/spl/php_spl_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/spl/spl_iterators.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,12 +3171,22 @@ PHP_FUNCTION(iterator_to_array)
31713171
zval *obj;
31723172
bool use_keys = 1;
31733173

3174-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &obj, zend_ce_traversable, &use_keys) == FAILURE) {
3175-
RETURN_THROWS();
3174+
ZEND_PARSE_PARAMETERS_START(1, 2)
3175+
Z_PARAM_ITERABLE(obj)
3176+
Z_PARAM_OPTIONAL
3177+
Z_PARAM_BOOL(use_keys)
3178+
ZEND_PARSE_PARAMETERS_END();
3179+
3180+
if (Z_TYPE_P(obj) == IS_ARRAY) {
3181+
if (use_keys) {
3182+
RETURN_COPY(obj);
3183+
} else {
3184+
RETVAL_ARR(zend_array_to_list(Z_ARRVAL_P(obj)));
3185+
}
3186+
} else {
3187+
array_init(return_value);
3188+
spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value);
31763189
}
3177-
3178-
array_init(return_value);
3179-
spl_iterator_apply(obj, use_keys ? spl_iterator_to_array_apply : spl_iterator_to_values_apply, (void*)return_value);
31803190
} /* }}} */
31813191

31823192
static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser) /* {{{ */

ext/spl/tests/iterator_to_array.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ iterator_to_array('test','test');
1313

1414
?>
1515
--EXPECTF--
16-
Fatal error: Uncaught TypeError: iterator_to_array(): Argument #1 ($iterator) must be of type Traversable, string given in %s:%d
16+
Fatal error: Uncaught TypeError: iterator_to_array(): Argument #1 ($iterator) must be of type Traversable|array, string given in %s:%d
1717
Stack trace:
1818
#0 %s(%d): iterator_to_array('test', 'test')
1919
#1 {main}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
SPL: iterator_to_array() supports arrays.
3+
--FILE--
4+
<?php
5+
6+
var_dump(iterator_to_array([]));
7+
var_dump(iterator_to_array([1]));
8+
var_dump(iterator_to_array(['a' => 1, 'b' => 2, 5 => 3]));
9+
var_dump(iterator_to_array([], false));
10+
var_dump(iterator_to_array([1], false));
11+
var_dump(iterator_to_array(['a' => 1, 'b' => 2, 5 => 3], false));
12+
13+
?>
14+
--EXPECT--
15+
array(0) {
16+
}
17+
array(1) {
18+
[0]=>
19+
int(1)
20+
}
21+
array(3) {
22+
["a"]=>
23+
int(1)
24+
["b"]=>
25+
int(2)
26+
[5]=>
27+
int(3)
28+
}
29+
array(0) {
30+
}
31+
array(1) {
32+
[0]=>
33+
int(1)
34+
}
35+
array(3) {
36+
[0]=>
37+
int(1)
38+
[1]=>
39+
int(2)
40+
[2]=>
41+
int(3)
42+
}

0 commit comments

Comments
 (0)