Skip to content

Commit 393199c

Browse files
committed
Follow foreach behaviour
1 parent b3cc8a8 commit 393199c

File tree

2 files changed

+60
-21
lines changed

2 files changed

+60
-21
lines changed

ext/standard/array.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,19 +1029,31 @@ static inline HashTable *get_ht_for_iap(zval *zv, bool separate) {
10291029
return zobj->handlers->get_properties(zobj);
10301030
}
10311031

1032-
static void ia_return_current(zval *return_value, HashTable *array)
1032+
static void ia_return_current(zval *return_value, HashTable *array, bool forward_direction)
10331033
{
10341034
zval *entry;
10351035

1036-
if ((entry = zend_hash_get_current_data(array)) == NULL) {
1037-
RETURN_FALSE;
1038-
}
1036+
while (true) {
1037+
if ((entry = zend_hash_get_current_data(array)) == NULL) {
1038+
RETURN_FALSE;
1039+
}
10391040

1040-
ZVAL_DEINDIRECT(entry);
1041+
ZVAL_DEINDIRECT(entry);
10411042

1042-
/* Possible with an uninitialized typed property */
1043-
if (Z_TYPE_P(entry) == IS_UNDEF) {
1044-
RETURN_FALSE;
1043+
/* Possible with an uninitialized typed property */
1044+
if (UNEXPECTED(Z_TYPE_P(entry) == IS_UNDEF)) {
1045+
zend_result result;
1046+
if (forward_direction) {
1047+
result = zend_hash_move_forward(array);
1048+
} else {
1049+
result = zend_hash_move_backwards(array);
1050+
}
1051+
if (result != SUCCESS) {
1052+
RETURN_FALSE;
1053+
}
1054+
} else {
1055+
break;
1056+
}
10451057
}
10461058

10471059
RETURN_COPY_DEREF(entry);
@@ -1064,7 +1076,7 @@ PHP_FUNCTION(end)
10641076
zend_hash_internal_pointer_end(array);
10651077

10661078
if (USED_RET()) {
1067-
ia_return_current(return_value, array);
1079+
ia_return_current(return_value, array, false);
10681080
}
10691081
}
10701082
/* }}} */
@@ -1086,7 +1098,7 @@ PHP_FUNCTION(prev)
10861098
zend_hash_move_backwards(array);
10871099

10881100
if (USED_RET()) {
1089-
ia_return_current(return_value, array);
1101+
ia_return_current(return_value, array, false);
10901102
}
10911103
}
10921104
/* }}} */
@@ -1108,7 +1120,7 @@ PHP_FUNCTION(next)
11081120
zend_hash_move_forward(array);
11091121

11101122
if (USED_RET()) {
1111-
ia_return_current(return_value, array);
1123+
ia_return_current(return_value, array, true);
11121124
}
11131125
}
11141126
/* }}} */
@@ -1130,7 +1142,7 @@ PHP_FUNCTION(reset)
11301142
zend_hash_internal_pointer_reset(array);
11311143

11321144
if (USED_RET()) {
1133-
ia_return_current(return_value, array);
1145+
ia_return_current(return_value, array, true);
11341146
}
11351147
}
11361148
/* }}} */
@@ -1145,7 +1157,7 @@ PHP_FUNCTION(current)
11451157
ZEND_PARSE_PARAMETERS_END();
11461158

11471159
HashTable *array = get_ht_for_iap(array_zv, /* separate */ false);
1148-
ia_return_current(return_value, array);
1160+
ia_return_current(return_value, array, true);
11491161
}
11501162
/* }}} */
11511163

ext/standard/tests/array/gh16905.phpt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,61 @@ GH-16905 (Internal iterator functions can't handle UNDEF properties)
33
--FILE--
44
<?php
55

6-
class X {
6+
class TestSomeUndef {
77
public int $a;
8+
public int $b;
9+
public int $c;
10+
public int $d;
811
}
912

10-
$x = new X;
13+
class TestAllUndef {
14+
public int $a;
15+
}
16+
17+
$x = new TestSomeUndef;
18+
$x->b = 1;
19+
$x->c = 2;
20+
1121
var_dump(reset($x));
1222
var_dump(current($x));
1323
var_dump(end($x));
24+
25+
var_dump(reset($x));
1426
var_dump(next($x));
27+
28+
var_dump(end($x));
1529
var_dump(prev($x));
30+
1631
var_dump(value: key($x));
1732

33+
$x = new TestAllUndef;
34+
var_dump(current($x));
35+
1836
?>
1937
--EXPECTF--
2038
Deprecated: reset(): Calling reset() on an object is deprecated in %s on line %d
21-
bool(false)
39+
int(1)
2240

2341
Deprecated: current(): Calling current() on an object is deprecated in %s on line %d
24-
bool(false)
42+
int(1)
2543

2644
Deprecated: end(): Calling end() on an object is deprecated in %s on line %d
27-
bool(false)
45+
int(2)
46+
47+
Deprecated: reset(): Calling reset() on an object is deprecated in %s on line %d
48+
int(1)
2849

2950
Deprecated: next(): Calling next() on an object is deprecated in %s on line %d
30-
bool(false)
51+
int(2)
52+
53+
Deprecated: end(): Calling end() on an object is deprecated in %s on line %d
54+
int(2)
3155

3256
Deprecated: prev(): Calling prev() on an object is deprecated in %s on line %d
33-
bool(false)
57+
int(1)
3458

3559
Deprecated: key(): Calling key() on an object is deprecated in %s on line %d
36-
NULL
60+
string(1) "b"
61+
62+
Deprecated: current(): Calling current() on an object is deprecated in %s on line %d
63+
bool(false)

0 commit comments

Comments
 (0)