From: Marcus Boerger Date: Sun, 21 May 2006 17:27:12 +0000 (+0000) Subject: - Make code exception safe X-Git-Tag: BEFORE_NEW_OUTPUT_API~126 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c7bf3183050bbcac7d451cf2c0a3c6a2249f7a96;p=php - Make code exception safe - Make RecursiveRegexIterator::getChildren pass regex to inner ctor - Fix CachingIterator::__toString() in TOSTRING_USE_KEY mode - Add CachingIterator::getCache() - Add tests --- diff --git a/ext/spl/spl_iterators.c b/ext/spl/spl_iterators.c index 6cdeeaca43..ce88d32312 100755 --- a/ext/spl/spl_iterators.c +++ b/ext/spl/spl_iterators.c @@ -193,6 +193,13 @@ next_step: switch (object->iterators[object->level].state) { case RS_NEXT: iterator->funcs->move_forward(iterator TSRMLS_CC); + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + return; + } else { + zend_clear_exception(TSRMLS_C); + } + } case RS_START: if (iterator->funcs->valid(iterator TSRMLS_CC) == FAILURE) { break; @@ -207,6 +214,14 @@ next_step: } else { zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval); } + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + object->iterators[object->level].state = RS_NEXT; + return; + } else { + zend_clear_exception(TSRMLS_C); + } + } if (retval) { has_children = zend_is_true(retval); zval_ptr_dtor(&retval); @@ -235,6 +250,13 @@ next_step: zend_call_method_with_0_params(&zthis, object->ce, &object->nextElement, "nextelement", NULL); } object->iterators[object->level].state = RS_NEXT; + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + return; + } else { + zend_clear_exception(TSRMLS_C); + } + } return /* self */; case RS_SELF: if (object->nextElement && (object->mode == RIT_SELF_FIRST || object->mode == RIT_CHILD_FIRST)) { @@ -292,6 +314,13 @@ next_step: } if (object->beginChildren) { zend_call_method_with_0_params(&zthis, object->ce, &object->beginChildren, "beginchildren", NULL); + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + return; + } else { + zend_clear_exception(TSRMLS_C); + } + } } goto next_step; } @@ -299,6 +328,13 @@ next_step: if (object->level > 0) { if (object->endChildren) { zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL); + if (EG(exception)) { + if (!(object->flags & RIT_CATCH_GET_CHILD)) { + return; + } else { + zend_clear_exception(TSRMLS_C); + } + } } iterator->funcs->dtor(iterator TSRMLS_CC); zval_ptr_dtor(&object->iterators[object->level].zobject); @@ -317,7 +353,7 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt sub_iter = object->iterators[object->level].iterator; sub_iter->funcs->dtor(sub_iter TSRMLS_CC); zval_ptr_dtor(&object->iterators[object->level--].zobject); - if (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator) { + if (!EG(exception) && (!object->endChildren || object->endChildren->common.scope != spl_ce_RecursiveIteratorIterator)) { zend_call_method_with_0_params(&zthis, object->ce, &object->endChildren, "endchildren", NULL); } } @@ -327,7 +363,7 @@ static void spl_recursive_it_rewind_ex(spl_recursive_it_object *object, zval *zt if (sub_iter->funcs->rewind) { sub_iter->funcs->rewind(sub_iter TSRMLS_CC); } - if (object->beginIteration && !object->in_iteration) { + if (!EG(exception) && object->beginIteration && !object->in_iteration) { zend_call_method_with_0_params(&zthis, object->ce, &object->beginIteration, "beginIteration", NULL); } object->in_iteration = 1; @@ -582,7 +618,11 @@ SPL_METHOD(RecursiveIteratorIterator, callHasChildren) RETURN_FALSE; } else { zend_call_method_with_0_params(&zobject, ce, NULL, "haschildren", &retval); - RETURN_ZVAL(retval, 0, 1); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } else { + RETURN_FALSE; + } } } /* }}} */ @@ -934,6 +974,13 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z } if (instanceof_function(ce, zend_ce_aggregate TSRMLS_CC)) { zend_call_method_with_0_params(&zobject, ce, &ce->iterator_funcs.zf_new_iterator, "getiterator", &retval); + if (EG(exception)) { + if (retval) { + zval_ptr_dtor(&retval); + } + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return NULL; + } if (!retval || Z_TYPE_P(retval) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(retval), zend_ce_traversable TSRMLS_CC)) { zend_throw_exception_ex(spl_ce_LogicException, 0 TSRMLS_CC, "%v::getIterator() must return an object that implememnts Traversable", ce->name); php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); @@ -964,6 +1011,7 @@ static spl_dual_it_object* spl_dual_it_construct(INTERNAL_FUNCTION_PARAMETERS, z php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); return NULL; } + intern->u.regex.regex = estrndup(regex, len); intern->u.regex.pce = pcre_get_compiled_regex_cache(regex, len, &extra, &poptions, &coptions TSRMLS_CC); intern->u.regex.pce->refcount++; break;; @@ -1252,7 +1300,11 @@ SPL_METHOD(RecursiveFilterIterator, hasChildren) intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); - RETURN_ZVAL(retval, 0, 1); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } else { + RETURN_FALSE; + } } /* }}} */ /* {{{ proto RecursiveFilterIterator RecursiveFilterIterator::getChildren() @@ -1265,8 +1317,10 @@ SPL_METHOD(RecursiveFilterIterator, getChildren) intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); - spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); - zval_ptr_dtor(&retval); + if (!EG(exception)) { + spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); + zval_ptr_dtor(&retval); + } } /* }}} */ /* {{{ proto void ParentIterator::__construct(RecursiveIterator it) @@ -1286,7 +1340,11 @@ SPL_METHOD(ParentIterator, hasChildren) intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); - RETURN_ZVAL(retval, 0, 1); + if (retval) { + RETURN_ZVAL(retval, 0, 1); + } else { + RETURN_FALSE; + } } /* }}} */ /* {{{ proto ParentIterator ParentIterator::getChildren() @@ -1299,8 +1357,10 @@ SPL_METHOD(ParentIterator, getChildren) intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); - spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); - zval_ptr_dtor(&retval); + if (retval) { + spl_instantiate_arg_ex1(Z_OBJCE_P(getThis()), &return_value, 0, retval TSRMLS_CC); + zval_ptr_dtor(&retval); + } } /* }}} */ #if HAVE_PCRE || HAVE_BUNDLED_PCRE @@ -1360,6 +1420,28 @@ SPL_METHOD(RecursiveRegexIterator, __construct) { spl_dual_it_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, spl_ce_RecursiveRegexIterator, spl_ce_RecursiveIterator, DIT_RecursiveRegexIterator); } /* }}} */ + +/* {{{ proto RecursiveRegexIterator RecursiveRegexIterator::getChildren() + Return the inner iterator's children contained in a RecursiveRegexIterator */ +SPL_METHOD(RecursiveRegexIterator, getChildren) +{ + spl_dual_it_object *intern; + zval *retval, *regex; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &retval); + if (!EG(exception)) { + MAKE_STD_ZVAL(regex); + ZVAL_STRING(regex, intern->u.regex.regex, 1); + spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, retval, regex TSRMLS_CC); + zval_ptr_dtor(®ex); + } + if (retval) { + zval_ptr_dtor(&retval); + } +} /* }}} */ + #endif /* {{{ spl_dual_it_free_storage */ @@ -1396,6 +1478,9 @@ static inline void spl_dual_it_free_storage(void *_object TSRMLS_DC) if (object->u.regex.pce) { object->u.regex.pce->refcount--; } + if (object->u.regex.regex) { + efree(object->u.regex.regex); + } } #endif @@ -1488,7 +1573,7 @@ ZEND_END_ARG_INFO(); static zend_function_entry spl_funcs_RecursiveRegexIterator[] = { SPL_ME(RecursiveRegexIterator, __construct, arginfo_rec_regex_it___construct, ZEND_ACC_PUBLIC) SPL_ME(ParentIterator, hasChildren, NULL, ZEND_ACC_PUBLIC) - SPL_ME(ParentIterator, getChildren, NULL, ZEND_ACC_PUBLIC) + SPL_ME(RecursiveRegexIterator, getChildren, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; #endif @@ -1522,9 +1607,11 @@ static inline void spl_limit_it_seek(spl_dual_it_object *intern, long pos TSRMLS spl_dual_it_free(intern TSRMLS_CC); zend_call_method_with_1_params(&intern->inner.zobject, intern->inner.ce, NULL, "seek", NULL, zpos); zval_ptr_dtor(&zpos); - intern->current.pos = pos; - if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) { - spl_dual_it_fetch(intern, 0 TSRMLS_CC); + if (!EG(exception)) { + intern->current.pos = pos; + if (spl_limit_it_valid(intern TSRMLS_CC) == SUCCESS) { + spl_dual_it_fetch(intern, 0 TSRMLS_CC); + } } } else { /* emulate the forward seek, by next() calls */ @@ -1675,25 +1762,43 @@ static inline void spl_caching_it_next(spl_dual_it_object *intern TSRMLS_DC) if (intern->dit_type == DIT_RecursiveCachingIterator) { zval *retval, *zchildren, zflags; zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "haschildren", &retval); - if (zend_is_true(retval)) { - zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren); - if (EG(exception)) { - if (zchildren) { + if (EG(exception)) { + if (retval) { + zval_ptr_dtor(&retval); + } + if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + zend_clear_exception(TSRMLS_C); + } else { + return; + } + } else { + if (zend_is_true(retval)) { + zend_call_method_with_0_params(&intern->inner.zobject, intern->inner.ce, NULL, "getchildren", &zchildren); + if (EG(exception)) { + if (zchildren) { + zval_ptr_dtor(&zchildren); + } + if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { + zend_clear_exception(TSRMLS_C); + } else { + return; + } + } else { + INIT_PZVAL(&zflags); + ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC); + spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC); zval_ptr_dtor(&zchildren); } + } + zval_ptr_dtor(&retval); + if (EG(exception)) { if (intern->u.caching.flags & CIT_CATCH_GET_CHILD) { zend_clear_exception(TSRMLS_C); } else { return; } - } else { - INIT_PZVAL(&zflags); - ZVAL_LONG(&zflags, intern->u.caching.flags & CIT_PUBLIC); - spl_instantiate_arg_ex2(spl_ce_RecursiveCachingIterator, &intern->u.caching.zchildren, 1, zchildren, &zflags TSRMLS_CC); - zval_ptr_dtor(&zchildren); } } - zval_ptr_dtor(&retval); } if (intern->u.caching.flags & (CIT_TOSTRING_USE_INNER|CIT_CALL_TOSTRING)) { int use_copy; @@ -1796,9 +1901,9 @@ SPL_METHOD(CachingIterator, __toString) } if (intern->u.caching.flags & CIT_TOSTRING_USE_KEY) { if (intern->current.key_type == HASH_KEY_IS_STRING) { - RETURN_STRINGL(intern->current.str_key.s, intern->current.str_key_len, 1); + RETURN_STRINGL(intern->current.str_key.s, intern->current.str_key_len-1, 1); } else if (intern->current.key_type == HASH_KEY_IS_UNICODE) { - RETURN_UNICODEL(intern->current.str_key.u, intern->current.str_key_len, 1); + RETURN_UNICODEL(intern->current.str_key.u, intern->current.str_key_len-1, 1); } else { RETVAL_LONG(intern->current.int_key); convert_to_text(return_value); @@ -1832,6 +1937,7 @@ SPL_METHOD(CachingIterator, offsetSet) if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Tz", &arKey, &nKeyLength, &type, &value) == FAILURE) { @@ -1857,6 +1963,7 @@ SPL_METHOD(CachingIterator, offsetGet) if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { @@ -1885,6 +1992,7 @@ SPL_METHOD(CachingIterator, offsetUnset) if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { @@ -1908,6 +2016,7 @@ SPL_METHOD(CachingIterator, offsetExists) if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "T", &arKey, &nKeyLength, &type) == FAILURE) { @@ -1918,6 +2027,23 @@ SPL_METHOD(CachingIterator, offsetExists) } /* }}} */ +/* {{{ proto bool CachingIterator::getCache() + Return the cache */ +SPL_METHOD(CachingIterator, getCache) +{ + spl_dual_it_object *intern; + + intern = (spl_dual_it_object*)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!(intern->u.caching.flags & CIT_FULL_CACHE)) { + zend_throw_exception_ex(spl_ce_BadMethodCallException, 0 TSRMLS_CC, "%v does not use a full cache (see CachingIterator::__construct)", Z_OBJCE_P(getThis())->name); + return; + } + + RETURN_ZVAL(intern->u.caching.zcache, 1, 0); +} +/* }}} */ + /* {{{ proto int CachingIterator::getFlags() Return the internal flags */ SPL_METHOD(CachingIterator, getFlags) @@ -2001,6 +2127,7 @@ static zend_function_entry spl_funcs_CachingIterator[] = { SPL_ME(CachingIterator, offsetSet, arginfo_caching_it_offsetSet, ZEND_ACC_PUBLIC) SPL_ME(CachingIterator, offsetUnset, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) SPL_ME(CachingIterator, offsetExists, arginfo_caching_it_offsetGet, ZEND_ACC_PUBLIC) + SPL_ME(CachingIterator, getCache, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; diff --git a/ext/spl/spl_iterators.h b/ext/spl/spl_iterators.h index ed74244e4f..dc03fd73da 100755 --- a/ext/spl/spl_iterators.h +++ b/ext/spl/spl_iterators.h @@ -130,6 +130,7 @@ typedef struct _spl_dual_it_object { struct { int flags; pcre_cache_entry *pce; + char *regex; } regex; #endif } u; diff --git a/ext/spl/tests/iterator_043.phpt b/ext/spl/tests/iterator_043.phpt new file mode 100755 index 0000000000..c49e334733 --- /dev/null +++ b/ext/spl/tests/iterator_043.phpt @@ -0,0 +1,20 @@ +--TEST-- +SPL: RecursiveCachingIterator and uninitialized getChildren() +--SKIPIF-- + +--FILE-- +getChildren()); +$it->rewind(); +var_dump($it->getChildren()); + +?> +===DONE=== + +--EXPECTF-- +NULL +NULL +===DONE=== diff --git a/ext/spl/tests/iterator_044.phpt b/ext/spl/tests/iterator_044.phpt new file mode 100755 index 0000000000..2cf1589109 --- /dev/null +++ b/ext/spl/tests/iterator_044.phpt @@ -0,0 +1,262 @@ +--TEST-- +SPL: CachingIterator and offsetGet/Exists using flag FULL_CACHE +--SKIPIF-- + +--FILE-- + $v) + { + echo "===$k===\n"; + var_dump($v); + var_dump($this->offsetExists($v)); + var_dump($this->offsetGet($v)); + } + } +} + +$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4))); + +try +{ + var_dump($it->offsetExists(0)); +} +catch(Exception $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +try +{ + var_dump($it->offsetGet(0)); +} +catch(Exception $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4)), CachingIterator::FULL_CACHE); + +var_dump($it->offsetExists()); +var_dump($it->offsetGet()); + +$checks = array(0, new stdClass, new MyFoo, NULL, 2, 'foo', 3); + +$it->test($checks); + +echo "===FILL===\n"; + +foreach($it as $v); // read all into cache + +$it->test($checks); + +?> +===DONE=== + +--EXPECTF-- +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) + +Warning: CachingIterator::offsetExists() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d +NULL +===0=== +int(0) +bool(false) + +Notice: Undefined index: 0 in %siterator_044.php on line %d +NULL +===1=== +object(stdClass)#%d (0) { +} + +Warning: CachingIterator::offsetExists() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL +===2=== +object(MyFoo)#%d (0) { +} +bool(false) + +Notice: Undefined index: foo in %siterator_044.php on line %d +NULL +===3=== +NULL +bool(false) + +Notice: Undefined index: in %siterator_044.php on line %d +NULL +===4=== +int(2) +bool(false) + +Notice: Undefined index: 2 in %siterator_044.php on line %d +NULL +===5=== +string(3) "foo" +bool(false) + +Notice: Undefined index: foo in %siterator_044.php on line %d +NULL +===6=== +int(3) +bool(false) + +Notice: Undefined index: 3 in %siterator_044.php on line %d +NULL +===FILL=== +===0=== +int(0) +bool(true) +int(0) +===1=== +object(stdClass)#1 (0) { +} + +Warning: CachingIterator::offsetExists() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL +===2=== +object(MyFoo)#2 (0) { +} +bool(true) +int(1) +===3=== +NULL +bool(false) + +Notice: Undefined index: in %siterator_044.php on line %d +NULL +===4=== +int(2) +bool(true) +int(4) +===5=== +string(3) "foo" +bool(true) +int(1) +===6=== +int(3) +bool(false) + +Notice: Undefined index: 3 in %siterator_044.php on line %d +NULL +===DONE=== +--UEXPECTF-- +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) + +Warning: CachingIterator::offsetExists() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects exactly 1 parameter, 0 given in %s/iterator_044.php on line %d +NULL +===0=== +int(0) +bool(false) + +Notice: Undefined index: 0 in %siterator_044.php on line %d +NULL +===1=== +object(stdClass)#%d (0) { +} + +Warning: CachingIterator::offsetExists() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL +===2=== +object(MyFoo)#%d (0) { +} +bool(false) + +Notice: Undefined index: foo in %siterator_044.php on line %d +NULL +===3=== +NULL +bool(false) + +Notice: Undefined index: in %siterator_044.php on line %d +NULL +===4=== +int(2) +bool(false) + +Notice: Undefined index: 2 in %siterator_044.php on line %d +NULL +===5=== +unicode(3) "foo" +bool(false) + +Notice: Undefined index: foo in %siterator_044.php on line %d +NULL +===6=== +int(3) +bool(false) + +Notice: Undefined index: 3 in %siterator_044.php on line %d +NULL +===FILL=== +===0=== +int(0) +bool(true) +int(0) +===1=== +object(stdClass)#1 (0) { +} + +Warning: CachingIterator::offsetExists() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL + +Warning: CachingIterator::offsetGet() expects parameter 1 to be string (Unicode or binary), object given in %siterator_044.php on line %d +NULL +===2=== +object(MyFoo)#2 (0) { +} +bool(true) +int(1) +===3=== +NULL +bool(false) + +Notice: Undefined index: in %siterator_044.php on line %d +NULL +===4=== +int(2) +bool(true) +int(4) +===5=== +unicode(3) "foo" +bool(true) +int(1) +===6=== +int(3) +bool(false) + +Notice: Undefined index: 3 in %siterator_044.php on line %d +NULL +===DONE=== diff --git a/ext/spl/tests/iterator_045.phpt b/ext/spl/tests/iterator_045.phpt new file mode 100755 index 0000000000..34dcfa78d1 --- /dev/null +++ b/ext/spl/tests/iterator_045.phpt @@ -0,0 +1,244 @@ +--TEST-- +SPL: CachingIterator and offsetSet/Unset, getCache using flag FULL_CACHE +--SKIPIF-- + +--FILE-- + $v) + { + echo "set($k,$v)\n"; + $this->offsetSet($k, $v); + } + } + + function testUnset($ar) + { + echo __METHOD__ . "()\n"; + foreach($ar as $k => $v) + { + echo "unset($v)\n"; + $this->offsetUnset($v); + } + } + + function fill() + { + echo __METHOD__ . "()\n"; + foreach($this as $v) ; + } + + function show() + { + echo __METHOD__ . "()\n"; + var_dump($this->getCache()); + } +} + +$it = new MyCachingIterator(new ArrayIterator(array(0, 'foo'=>1, 2, 'bar'=>3, 4))); + +try +{ + var_dump($it->offsetSet(0, 0)); +} +catch(Exception $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +try +{ + var_dump($it->offsetUnset(0)); +} +catch(Exception $e) +{ + echo "Exception: " . $e->getMessage() . "\n"; +} + +$it = new MyCachingIterator(new ArrayIterator(array(0, 1, 2, 3)), CachingIterator::FULL_CACHE); + +var_dump($it->offsetSet()); +var_dump($it->offsetSet(0)); +var_dump($it->offsetUnset()); + +$checks = array(0 => 25, 1 => 42, 3 => 'FooBar'); +$unsets = array(0, 2); + +$it->testSet($checks); +$it->show(); +$it->testUnset($unsets); +$it->show(); +$it->fill(); +$it->show(); +$it->testSet($checks); +$it->show(); +$it->testUnset($unsets); +$it->show(); + +?> +===DONE=== + +--EXPECTF-- +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) + +Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 0 given in %siterator_045.php on line %d +NULL + +Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 1 given in %siterator_045.php on line %d +NULL + +Warning: CachingIterator::offsetUnset() expects exactly 1 parameter, 0 given in %siterator_045.php on line %d +NULL +MyCachingIterator::testSet() +set(0,25) +set(1,42) +set(3,FooBar) +MyCachingIterator::show() +array(3) { + [0]=> + int(25) + [1]=> + int(42) + [3]=> + string(6) "FooBar" +} +MyCachingIterator::testUnset() +unset(0) +unset(2) +MyCachingIterator::show() +array(2) { + [1]=> + int(42) + [3]=> + string(6) "FooBar" +} +MyCachingIterator::fill() +MyCachingIterator::show() +array(4) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) +} +MyCachingIterator::testSet() +set(0,25) +set(1,42) +set(3,FooBar) +MyCachingIterator::show() +array(4) { + [0]=> + int(25) + [1]=> + int(42) + [2]=> + int(2) + [3]=> + string(6) "FooBar" +} +MyCachingIterator::testUnset() +unset(0) +unset(2) +MyCachingIterator::show() +array(2) { + [1]=> + int(42) + [3]=> + string(6) "FooBar" +} +===DONE=== +--UEXPECTF-- +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) +Exception: MyCachingIterator does not use a full cache (see CachingIterator::__construct) + +Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 0 given in %siterator_045.php on line %d +NULL + +Warning: CachingIterator::offsetSet() expects exactly 2 parameters, 1 given in %siterator_045.php on line %d +NULL + +Warning: CachingIterator::offsetUnset() expects exactly 1 parameter, 0 given in %siterator_045.php on line %d +NULL +MyCachingIterator::testSet() +set(0,25) +set(1,42) +set(3,FooBar) +MyCachingIterator::show() +array(3) { + [0]=> + int(25) + [1]=> + int(42) + [3]=> + unicode(6) "FooBar" +} +MyCachingIterator::testUnset() +unset(0) +unset(2) +MyCachingIterator::show() +array(2) { + [1]=> + int(42) + [3]=> + unicode(6) "FooBar" +} +MyCachingIterator::fill() +MyCachingIterator::show() +array(4) { + [0]=> + int(0) + [1]=> + int(1) + [2]=> + int(2) + [3]=> + int(3) +} +MyCachingIterator::testSet() +set(0,25) +set(1,42) +set(3,FooBar) +MyCachingIterator::show() +array(4) { + [0]=> + int(25) + [1]=> + int(42) + [2]=> + int(2) + [3]=> + unicode(6) "FooBar" +} +MyCachingIterator::testUnset() +unset(0) +unset(2) +MyCachingIterator::show() +array(2) { + [1]=> + int(42) + [3]=> + unicode(6) "FooBar" +} +===DONE=== diff --git a/ext/spl/tests/iterator_046.phpt b/ext/spl/tests/iterator_046.phpt new file mode 100755 index 0000000000..35736c4110 --- /dev/null +++ b/ext/spl/tests/iterator_046.phpt @@ -0,0 +1,60 @@ +--TEST-- +SPL: CachingIterator and __toString using bypassed string keys +--SKIPIF-- + +--FILE-- +1, 'bar'=>2)), CachingIterator::TOSTRING_USE_KEY); + +$it->fill(); +$it->show(); + +?> +===DONE=== + +--EXPECTF-- +MyCachingIterator::fill() +MyCachingIterator::show() +string(1) "0" +string(3) "foo" +string(3) "bar" +===DONE=== +--UEXPECTF-- +MyCachingIterator::fill() +MyCachingIterator::show() +unicode(1) "0" +unicode(3) "foo" +unicode(3) "bar" +===DONE=== diff --git a/ext/spl/tests/iterator_047.phpt b/ext/spl/tests/iterator_047.phpt new file mode 100755 index 0000000000..b313df3012 --- /dev/null +++ b/ext/spl/tests/iterator_047.phpt @@ -0,0 +1,119 @@ +--TEST-- +SPL: RecursiveCachingIterator and exception in has/getChildren +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } + catch (Exception $e) + { + echo "Exception: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine() . "\n"; + } + MyRecursiveArrayIterator::$fail++; + } + } +} + +$it = new MyRecursiveArrayIterator(array(0, array(10), 2, array(30), 4)); +$it = new MyRecursiveCachingIterator($it); + +$it->show(); + +?> +===DONE=== + +--EXPECTF-- +===0=== +MyRecursiveArrayIterator::hasChildren() +int(0) +int(0) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::hasChildren() +int(0) +int(10) +MyRecursiveArrayIterator::hasChildren() +int(2) +int(2) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::hasChildren() +int(0) +int(30) +MyRecursiveArrayIterator::hasChildren() +int(4) +int(4) +===1=== +MyRecursiveArrayIterator::hasChildren() +Exception: State 1: MyRecursiveArrayIterator::hasChildren() in %siterator_047.php on line %d +===2=== +MyRecursiveArrayIterator::hasChildren() +int(0) +int(0) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +Exception: State 2: MyRecursiveArrayIterator::getChildren() in %siterator_047.php on line %d +===3=== +MyRecursiveArrayIterator::hasChildren() +int(0) +int(0) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::hasChildren() +int(0) +int(10) +MyRecursiveArrayIterator::hasChildren() +int(2) +int(2) +MyRecursiveArrayIterator::hasChildren() +MyRecursiveArrayIterator::getChildren() +MyRecursiveArrayIterator::hasChildren() +int(0) +int(30) +MyRecursiveArrayIterator::hasChildren() +int(4) +int(4) +===DONE=== diff --git a/ext/spl/tests/iterator_048.phpt b/ext/spl/tests/iterator_048.phpt new file mode 100755 index 0000000000..feea20461a --- /dev/null +++ b/ext/spl/tests/iterator_048.phpt @@ -0,0 +1,44 @@ +--TEST-- +SPL: RecursiveCachingIterator and exception in has/getChildren +--SKIPIF-- + +--FILE-- + $v) + { + var_dump($k); + var_dump($v); + } + } + + function accept() + { + return $this->hasChildren() || parent::accept(); + } +} + +$ar = new RecursiveArrayIterator(array('Foo', array('Bar'), 'FooBar', array('Baz'), 'Biz')); +$it = new MyRecursiveRegexIterator($ar, '/Bar/'); + +$it->show(); + +?> +===DONE=== + +--EXPECTF-- +int(0) +string(3) "Bar" +int(2) +string(6) "FooBar" +===DONE=== +--UEXPECTF-- +int(0) +unicode(3) "Bar" +int(2) +unicode(6) "FooBar" +===DONE===