Skip to content

Commit 27e55df

Browse files
committed
Iterators
1 parent 1c697fb commit 27e55df

16 files changed

+120
-126
lines changed

ext/spl/spl_iterators.c

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,16 @@ static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *ob
131131
do { \
132132
spl_dual_it_object *it = Z_SPLDUAL_IT_P(objzval); \
133133
if (it->dit_type == DIT_Unknown) { \
134-
zend_throw_exception_ex(spl_ce_LogicException, 0, \
135-
"The object is in an invalid state as the parent constructor was not called"); \
136-
RETURN_THROWS(); \
134+
zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
135+
RETURN_THROWS(); \
137136
} \
138137
(var) = it; \
139138
} while (0)
140139

141140
#define SPL_FETCH_SUB_ELEMENT(var, object, element) \
142141
do { \
143142
if(!(object)->iterators) { \
144-
zend_throw_exception_ex(spl_ce_LogicException, 0, \
145-
"The object is in an invalid state as the parent constructor was not called"); \
143+
zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
146144
return; \
147145
} \
148146
(var) = (object)->iterators[(object)->level].element; \
@@ -151,8 +149,7 @@ static inline spl_recursive_it_object *spl_recursive_it_from_obj(zend_object *ob
151149
#define SPL_FETCH_SUB_ELEMENT_ADDR(var, object, element) \
152150
do { \
153151
if(!(object)->iterators) { \
154-
zend_throw_exception_ex(spl_ce_LogicException, 0, \
155-
"The object is in an invalid state as the parent constructor was not called"); \
152+
zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called"); \
156153
RETURN_THROWS(); \
157154
} \
158155
(var) = &(object)->iterators[(object)->level].element; \
@@ -258,7 +255,7 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
258255
break;
259256
}
260257
object->iterators[object->level].state = RS_TEST;
261-
/* break; */
258+
/* break; */ // wat?
262259
case RS_TEST:
263260
ce = object->iterators[object->level].ce;
264261
zobject = &object->iterators[object->level].zobject;
@@ -343,8 +340,9 @@ static void spl_recursive_it_move_forward_ex(spl_recursive_it_object *object, zv
343340

344341
if (Z_TYPE(child) == IS_UNDEF || Z_TYPE(child) != IS_OBJECT ||
345342
!((ce = Z_OBJCE(child)) && instanceof_function(ce, spl_ce_RecursiveIterator))) {
343+
zend_type_error("Return value of RecursiveIterator::getChildren() must be of type RecursiveIterator, %s returned",
344+
zend_zval_type_name(&child));
346345
zval_ptr_dtor(&child);
347-
zend_throw_exception(spl_ce_UnexpectedValueException, "Objects returned by RecursiveIterator::getChildren() must implement RecursiveIterator", 0);
348346
return;
349347
}
350348

@@ -453,13 +451,13 @@ static zend_object_iterator *spl_recursive_it_get_iterator(zend_class_entry *ce,
453451
spl_recursive_it_object *object;
454452

455453
if (by_ref) {
456-
zend_throw_exception(spl_ce_RuntimeException, "An iterator cannot be used with foreach by reference", 0);
454+
zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
457455
return NULL;
458456
}
459457
iterator = emalloc(sizeof(spl_recursive_it_iterator));
460458
object = Z_SPLRECURSIVE_IT_P(zobject);
461459
if (object->iterators == NULL) {
462-
zend_error(E_ERROR, "The object to be iterated is in an invalid state: "
460+
zend_throw_error(NULL, "The object to be iterated is in an invalid state: "
463461
"the parent constructor has not been called");
464462
}
465463

@@ -529,7 +527,7 @@ static void spl_recursive_it_it_construct(INTERNAL_FUNCTION_PARAMETERS, zend_cla
529527
if (iterator) {
530528
zval_ptr_dtor(iterator);
531529
}
532-
zend_throw_exception(spl_ce_InvalidArgumentException, "An instance of RecursiveIterator or IteratorAggregate creating it is required", 0);
530+
zend_throw_error(NULL, "An instance of RecursiveIterator or IteratorAggregate creating it is required");
533531
zend_restore_error_handling(&error_handling);
534532
return;
535533
}
@@ -708,8 +706,7 @@ SPL_METHOD(RecursiveIteratorIterator, getSubIterator)
708706
}
709707

710708
if(!object->iterators) {
711-
zend_throw_exception_ex(spl_ce_LogicException, 0,
712-
"The object is in an invalid state as the parent constructor was not called");
709+
zend_throw_error(NULL, "The object is in an invalid state as the parent constructor was not called");
713710
RETURN_THROWS();
714711
}
715712

@@ -848,7 +845,7 @@ SPL_METHOD(RecursiveIteratorIterator, setMaxDepth)
848845
RETURN_THROWS();
849846
}
850847
if (max_depth < -1) {
851-
zend_value_error("Parameter max_depth must be greater or equal than -1");
848+
zend_argument_value_error(1, "must be greater or equal than -1");
852849
RETURN_THROWS();
853850
} else if (max_depth > INT_MAX) {
854851
max_depth = INT_MAX;
@@ -882,7 +879,8 @@ static zend_function *spl_recursive_it_get_method(zend_object **zobject, zend_st
882879
zval *zobj;
883880

884881
if (!object->iterators) {
885-
php_error_docref(NULL, E_ERROR, "The %s instance wasn't initialized properly", ZSTR_VAL((*zobject)->ce->name));
882+
zend_throw_error(NULL, "The %s instance wasn't initialized properly",
883+
ZSTR_VAL((*zobject)->ce->name));
886884
}
887885
zobj = &object->iterators[level].zobject;
888886

@@ -1084,7 +1082,7 @@ SPL_METHOD(RecursiveTreeIterator, setPrefixPart)
10841082
}
10851083

10861084
if (0 > part || part > 5) {
1087-
zend_value_error("Use RecursiveTreeIterator::PREFIX_* constant");
1085+
zend_argument_value_error(2, "must be one of RecursiveTreeIterator::PREFIX_*");
10881086
RETURN_THROWS();
10891087
}
10901088

@@ -1103,7 +1101,7 @@ SPL_METHOD(RecursiveTreeIterator, getPrefix)
11031101
}
11041102

11051103
if(!object->iterators) {
1106-
zend_throw_exception_ex(spl_ce_LogicException, 0,
1104+
zend_throw_error(NULL,
11071105
"The object is in an invalid state as the parent constructor was not called");
11081106
RETURN_THROWS();
11091107
}
@@ -1138,7 +1136,7 @@ SPL_METHOD(RecursiveTreeIterator, getEntry)
11381136
}
11391137

11401138
if(!object->iterators) {
1141-
zend_throw_exception_ex(spl_ce_LogicException, 0,
1139+
zend_throw_error(NULL,
11421140
"The object is in an invalid state as the parent constructor was not called");
11431141
RETURN_THROWS();
11441142
}
@@ -1157,7 +1155,7 @@ SPL_METHOD(RecursiveTreeIterator, getPostfix)
11571155
}
11581156

11591157
if(!object->iterators) {
1160-
zend_throw_exception_ex(spl_ce_LogicException, 0,
1158+
zend_throw_error(NULL,
11611159
"The object is in an invalid state as the parent constructor was not called");
11621160
RETURN_THROWS();
11631161
}
@@ -1179,7 +1177,7 @@ SPL_METHOD(RecursiveTreeIterator, current)
11791177
}
11801178

11811179
if(!object->iterators) {
1182-
zend_throw_exception_ex(spl_ce_LogicException, 0,
1180+
zend_throw_error(NULL,
11831181
"The object is in an invalid state as the parent constructor was not called");
11841182
RETURN_THROWS();
11851183
}
@@ -1325,7 +1323,7 @@ static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *
13251323

13261324
#define SPL_CHECK_CTOR(intern, classname) \
13271325
if (intern->dit_type == DIT_Unknown) { \
1328-
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Classes derived from %s must call %s::__construct()", \
1326+
zend_throw_error(NULL, "Classes derived from %s must call %s::__construct()", \
13291327
ZSTR_VAL((spl_ce_##classname)->name), ZSTR_VAL((spl_ce_##classname)->name)); \
13301328
RETURN_THROWS(); \
13311329
}
@@ -1357,7 +1355,8 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
13571355
intern = Z_SPLDUAL_IT_P(ZEND_THIS);
13581356

13591357
if (intern->dit_type != DIT_Unknown) {
1360-
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s::getIterator() must be called exactly once per instance", ZSTR_VAL(ce_base->name));
1358+
zend_throw_error(NULL, "%s::getIterator() must be called exactly once per instance",
1359+
ZSTR_VAL(ce_base->name));
13611360
return NULL;
13621361
}
13631362

@@ -1370,11 +1369,11 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
13701369
return NULL;
13711370
}
13721371
if (intern->u.limit.offset < 0) {
1373-
zend_value_error("Parameter offset must be >= 0");
1372+
zend_argument_value_error(1, "must be greater or equal to 0");
13741373
return NULL;
13751374
}
13761375
if (intern->u.limit.count < 0 && intern->u.limit.count != -1) {
1377-
zend_value_error("Parameter count must either be -1 or a value greater than or equal 0");
1376+
zend_argument_value_error(2, "must be greater or equal to 0");
13781377
return NULL;
13791378
}
13801379
break;
@@ -1386,7 +1385,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
13861385
return NULL;
13871386
}
13881387
if (spl_cit_check_flags(flags) != SUCCESS) {
1389-
zend_value_error("Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER");
1388+
zend_argument_value_error(2, "must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER");
13901389
return NULL;
13911390
}
13921391
intern->u.caching.flags |= flags & CIT_PUBLIC;
@@ -1407,7 +1406,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
14071406
|| !instanceof_function(ce, ce_cast)
14081407
|| !ce_cast->get_iterator
14091408
) {
1410-
zend_type_error("Class to downcast to not found or not base class or does not implement Traversable");
1409+
zend_argument_type_error(1, "Class to downcast to not found or not base class or does not implement Traversable");
14111410
return NULL;
14121411
}
14131412
ce = ce_cast;
@@ -1419,7 +1418,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
14191418
return NULL;
14201419
}
14211420
if (Z_TYPE(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE(retval), zend_ce_traversable)) {
1422-
zend_type_error("%s::getIterator() must return an object that implements Traversable", ZSTR_VAL(ce->name));
1421+
zend_type_error("Return value of %s::getIterator() must be Traversable", ZSTR_VAL(ce->name));
14231422
return NULL;
14241423
}
14251424
zobject = &retval;
@@ -1451,7 +1450,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z
14511450
return NULL;
14521451
}
14531452
if (mode < 0 || mode >= REGIT_MODE_MAX) {
1454-
zend_value_error("Illegal mode " ZEND_LONG_FMT, mode);
1453+
zend_argument_value_error(3, "is illegal");
14551454
return NULL;
14561455
}
14571456
intern->u.regex.mode = mode;
@@ -2331,11 +2330,11 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, zend_long pos)
23312330

23322331
spl_dual_it_free(intern);
23332332
if (pos < intern->u.limit.offset) {
2334-
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is below the offset " ZEND_LONG_FMT, pos, intern->u.limit.offset);
2333+
zend_value_error("Seek position is out of bounds");
23352334
return;
23362335
}
23372336
if (pos >= intern->u.limit.offset + intern->u.limit.count && intern->u.limit.count != -1) {
2338-
zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Cannot seek to " ZEND_LONG_FMT " which is behind offset " ZEND_LONG_FMT " plus count " ZEND_LONG_FMT, pos, intern->u.limit.offset, intern->u.limit.count);
2337+
zend_value_error("Seek position is out of bounds");
23392338
return;
23402339
}
23412340
if (pos != intern->current.pos && instanceof_function(intern->inner.ce, spl_ce_SeekableIterator)) {
@@ -2637,6 +2636,7 @@ SPL_METHOD(CachingIterator, __toString)
26372636
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
26382637

26392638
if (!(intern->u.caching.flags & (CIT_CALL_TOSTRING|CIT_TOSTRING_USE_KEY|CIT_TOSTRING_USE_CURRENT|CIT_TOSTRING_USE_INNER))) {
2639+
// Todo conversion
26402640
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not fetch string value (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
26412641
RETURN_THROWS();
26422642
}
@@ -2672,6 +2672,7 @@ SPL_METHOD(CachingIterator, offsetSet)
26722672
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
26732673

26742674
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2675+
// Todo convert to standard exception
26752676
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
26762677
RETURN_THROWS();
26772678
}
@@ -2696,6 +2697,7 @@ SPL_METHOD(CachingIterator, offsetGet)
26962697
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
26972698

26982699
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2700+
// Todo convert to standard exception
26992701
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
27002702
RETURN_THROWS();
27012703
}
@@ -2723,6 +2725,7 @@ SPL_METHOD(CachingIterator, offsetUnset)
27232725
}
27242726

27252727
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2728+
// Todo convert to standard exception
27262729
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
27272730
RETURN_THROWS();
27282731
}
@@ -2745,6 +2748,7 @@ SPL_METHOD(CachingIterator, offsetExists)
27452748
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
27462749

27472750
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2751+
// Todo convert to standard exception
27482752
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
27492753
RETURN_THROWS();
27502754
}
@@ -2766,6 +2770,7 @@ SPL_METHOD(CachingIterator, getCache)
27662770
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
27672771

27682772
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2773+
// Todo convert to standard exception
27692774
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
27702775
RETURN_THROWS();
27712776
}
@@ -2804,15 +2809,15 @@ SPL_METHOD(CachingIterator, setFlags)
28042809
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
28052810

28062811
if (spl_cit_check_flags(flags) != SUCCESS) {
2807-
zend_value_error("Flags must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER");
2812+
zend_argument_value_error(1, "must contain only one of CALL_TOSTRING, TOSTRING_USE_KEY, TOSTRING_USE_CURRENT, TOSTRING_USE_INNER");
28082813
RETURN_THROWS();
28092814
}
28102815
if ((intern->u.caching.flags & CIT_CALL_TOSTRING) != 0 && (flags & CIT_CALL_TOSTRING) == 0) {
2811-
zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag CALL_TO_STRING is not possible", 0);
2816+
zend_argument_value_error(1, "cannot unset flag CALL_TO_STRING", 0);
28122817
RETURN_THROWS();
28132818
}
28142819
if ((intern->u.caching.flags & CIT_TOSTRING_USE_INNER) != 0 && (flags & CIT_TOSTRING_USE_INNER) == 0) {
2815-
zend_throw_exception(spl_ce_InvalidArgumentException, "Unsetting flag TOSTRING_USE_INNER is not possible", 0);
2820+
zend_argument_value_error(1, "cannot unset flag TOSTRING_USE_INNER", 0);
28162821
RETURN_THROWS();
28172822
}
28182823
if ((flags & CIT_FULL_CACHE) != 0 && (intern->u.caching.flags & CIT_FULL_CACHE) == 0) {
@@ -2836,6 +2841,7 @@ SPL_METHOD(CachingIterator, count)
28362841
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);
28372842

28382843
if (!(intern->u.caching.flags & CIT_FULL_CACHE)) {
2844+
// Todo convert to standard exception
28392845
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s does not use a full cache (see CachingIterator::__construct)", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
28402846
RETURN_THROWS();
28412847
}
@@ -3090,7 +3096,7 @@ SPL_METHOD(EmptyIterator, key)
30903096
RETURN_THROWS();
30913097
}
30923098

3093-
zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the key of an EmptyIterator", 0);
3099+
zend_throw_error(NULL, "Accessing the key of an EmptyIterator");
30943100
} /* }}} */
30953101

30963102
/* {{{ proto void EmptyIterator::current()
@@ -3101,7 +3107,7 @@ SPL_METHOD(EmptyIterator, current)
31013107
RETURN_THROWS();
31023108
}
31033109

3104-
zend_throw_exception(spl_ce_BadMethodCallException, "Accessing the value of an EmptyIterator", 0);
3110+
zend_throw_error(NULL, "Accessing the value of an EmptyIterator");
31053111
} /* }}} */
31063112

31073113
/* {{{ proto void EmptyIterator::next()

ext/spl/tests/bug41828.phpt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ class foo extends RecursiveIteratorIterator {
1212
}
1313

1414
$foo = new foo("This is bar");
15-
echo $foo->bar();
15+
try {
16+
echo $foo->bar();
17+
} catch (Error $e) {
18+
echo $e->getMessage() . \PHP_EOL;
19+
}
1620

1721
?>
18-
==DONE==
19-
<?php exit(0); ?>
20-
--EXPECTF--
21-
Fatal error: main(): The foo instance wasn't initialized properly in %s on line %d
22+
--EXPECT--
23+
The foo instance wasn't initialized properly

ext/spl/tests/bug51119.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ try {
2929
a
3030
b
3131
c
32-
Parameter offset must be >= 0
32+
LimitIterator::__construct(): Argument #1 ($iterator) must be greater or equal to 0

ext/spl/tests/bug54281.phpt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ class RecursiveArrayIteratorIterator extends RecursiveIteratorIterator {
88
}
99
$it = new RecursiveArrayIteratorIterator(new RecursiveArrayIterator(array()), 2);
1010

11-
foreach($it as $k=>$v) { }
11+
try {
12+
foreach($it as $k=>$v) { }
13+
} catch (\Error $e) {
14+
echo $e->getMessage() . \PHP_EOL;
15+
}
1216

1317
?>
14-
--EXPECTF--
15-
Fatal error: Uncaught LogicException: The object is in an invalid state as the parent constructor was not called in %s:%d
16-
Stack trace:
17-
#0 %s%ebug54281.php(8): RecursiveIteratorIterator->rewind()
18-
#1 {main}
19-
thrown in %s%ebug54281.php on line 8
18+
--EXPECT--
19+
The object is in an invalid state as the parent constructor was not called

0 commit comments

Comments
 (0)