helly Sat May 20 21:01:42 2006 UTC Added files: (Branch: PHP_5_2) /php-src/ext/spl/tests iterator_041.phpt iterator_041a.phpt iterator_041b.phpt
Modified files: /php-src/ext/spl spl_iterators.c spl_iterators.h Log: - MFH Sync with head fixes part of an issue with iterator_(to_array|count)
http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.c?r1=1.73.2.30.2.7&r2=1.73.2.30.2.8&diff_format=u Index: php-src/ext/spl/spl_iterators.c diff -u php-src/ext/spl/spl_iterators.c:1.73.2.30.2.7 php-src/ext/spl/spl_iterators.c:1.73.2.30.2.8 --- php-src/ext/spl/spl_iterators.c:1.73.2.30.2.7 Thu May 18 21:48:33 2006 +++ php-src/ext/spl/spl_iterators.c Sat May 20 21:01:42 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_iterators.c,v 1.73.2.30.2.7 2006/05/18 21:48:33 helly Exp $ */ +/* $Id: spl_iterators.c,v 1.73.2.30.2.8 2006/05/20 21:01:42 helly Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -2372,63 +2372,100 @@ {NULL, NULL, NULL} }; -/* {{{ proto array iterator_to_array(Traversable it) - Copy the iterator into an array */ -PHP_FUNCTION(iterator_to_array) +PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC) { - zval *obj, **data; zend_object_iterator *iter; - char *str_key; - uint str_key_len; - ulong int_key; - int key_type; + zend_class_entry *ce = Z_OBJCE_P(obj); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) { - RETURN_FALSE; + iter = ce->get_iterator(ce, obj, 0 TSRMLS_CC); + + if (EG(exception)) { + goto done; } - - array_init(return_value); - - iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj, 0 TSRMLS_CC); if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); + if (EG(exception)) { + goto done; + } } - if (EG(exception)) { - return; - } + while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) { - iter->funcs->get_current_data(iter, &data TSRMLS_CC); if (EG(exception)) { - return; + goto done; } - (*data)->refcount++; - if (iter->funcs->get_current_key) { - key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); - if (EG(exception)) { - return; - } - switch(key_type) { - case HASH_KEY_IS_STRING: - add_assoc_zval_ex(return_value, str_key, str_key_len, *data); - efree(str_key); - break; - case HASH_KEY_IS_LONG: - add_index_zval(return_value, int_key, *data); - break; - } - } else { - add_next_index_zval(return_value, *data); + if (apply_func(iter, puser TSRMLS_CC) == ZEND_HASH_APPLY_STOP || EG(exception)) { + goto done; } iter->funcs->move_forward(iter TSRMLS_CC); if (EG(exception)) { - return; + goto done; } } + +done: iter->funcs->dtor(iter TSRMLS_CC); + return EG(exception) ? FAILURE : SUCCESS; +} +/* }}} */ + +static int spl_iterator_to_array_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ +{ + zval **data, *return_value = (zval*)puser; + char *str_key; + uint str_key_len; + ulong int_key; + int key_type; + + iter->funcs->get_current_data(iter, &data TSRMLS_CC); if (EG(exception)) { - return; + return ZEND_HASH_APPLY_STOP; + } + if (iter->funcs->get_current_key) { + key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); + if (EG(exception)) { + return ZEND_HASH_APPLY_STOP; + } + (*data)->refcount++; + switch(key_type) { + case HASH_KEY_IS_STRING: + add_assoc_zval_ex(return_value, str_key, str_key_len, *data); + efree(str_key); + break; + case HASH_KEY_IS_LONG: + add_index_zval(return_value, int_key, *data); + break; + } + } else { + (*data)->refcount++; + add_next_index_zval(return_value, *data); + } + return ZEND_HASH_APPLY_KEEP; +} +/* }}} */ + +/* {{{ proto array iterator_to_array(Traversable it) + Copy the iterator into an array */ +PHP_FUNCTION(iterator_to_array) +{ + zval *obj; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) { + RETURN_FALSE; } + + array_init(return_value); + + if (spl_iterator_apply(obj, spl_iterator_to_array_apply, (void*)return_value TSRMLS_CC) != SUCCESS) { + zval_dtor(return_value); + RETURN_NULL(); + } +} + +static int spl_iterator_count_apply(zend_object_iterator *iter, void *puser TSRMLS_DC) /* {{{ */ +{ + (*(long*)puser)++; + return ZEND_HASH_APPLY_KEEP; } /* }}} */ @@ -2437,37 +2474,15 @@ PHP_FUNCTION(iterator_count) { zval *obj; - zend_object_iterator *iter; long count = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, zend_ce_traversable) == FAILURE) { RETURN_FALSE; } - iter = Z_OBJCE_P(obj)->get_iterator(Z_OBJCE_P(obj), obj, 0 TSRMLS_CC); - - if (iter->funcs->rewind) { - iter->funcs->rewind(iter TSRMLS_CC); + if (spl_iterator_apply(obj, spl_iterator_count_apply, (void*)&count TSRMLS_CC) == SUCCESS) { + RETURN_LONG(count); } - if (EG(exception)) { - return; - } - while (iter->funcs->valid(iter TSRMLS_CC) == SUCCESS) { - if (EG(exception)) { - return; - } - count++; - iter->funcs->move_forward(iter TSRMLS_CC); - if (EG(exception)) { - return; - } - } - iter->funcs->dtor(iter TSRMLS_CC); - if (EG(exception)) { - return; - } - - RETURN_LONG(count); } /* }}} */ @@ -2529,7 +2544,7 @@ REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "CATCH_GET_CHILD", CIT_CATCH_GET_CHILD); REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_KEY", CIT_TOSTRING_USE_KEY); REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_CURRENT", CIT_TOSTRING_USE_CURRENT); - REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER",CIT_TOSTRING_USE_INNER); + REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "TOSTRING_USE_INNER", CIT_TOSTRING_USE_INNER); REGISTER_SPL_CLASS_CONST_LONG(CachingIterator, "FULL_CACHE", CIT_FULL_CACHE); REGISTER_SPL_SUB_CLASS_EX(RecursiveCachingIterator, CachingIterator, spl_dual_it_new, spl_funcs_RecursiveCachingIterator); http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/spl_iterators.h?r1=1.18.2.7.2.3&r2=1.18.2.7.2.4&diff_format=u Index: php-src/ext/spl/spl_iterators.h diff -u php-src/ext/spl/spl_iterators.h:1.18.2.7.2.3 php-src/ext/spl/spl_iterators.h:1.18.2.7.2.4 --- php-src/ext/spl/spl_iterators.h:1.18.2.7.2.3 Thu May 18 21:42:58 2006 +++ php-src/ext/spl/spl_iterators.h Sat May 20 21:01:42 2006 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_iterators.h,v 1.18.2.7.2.3 2006/05/18 21:42:58 helly Exp $ */ +/* $Id: spl_iterators.h,v 1.18.2.7.2.4 2006/05/20 21:01:42 helly Exp $ */ #ifndef SPL_ITERATORS_H #define SPL_ITERATORS_H @@ -135,6 +135,10 @@ } u; } spl_dual_it_object; +typedef int (*spl_iterator_apply_func_t)(zend_object_iterator *iter, void *puser TSRMLS_DC); + +PHPAPI int spl_iterator_apply(zval *obj, spl_iterator_apply_func_t apply_func, void *puser TSRMLS_DC); + #endif /* SPL_ITERATORS_H */ /* http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_041.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/iterator_041.phpt +++ php-src/ext/spl/tests/iterator_041.phpt --TEST-- SPL: iterator_to_array() and exceptions --SKIPIF-- <?php if (!extension_loaded("spl")) print "skip"; ?> --FILE-- <?php class MyArrayIterator extends ArrayIterator { static protected $fail = 0; static function fail($state, $method) { if (self::$fail == $state) { throw new Exception("State $state: $method()"); } } function __construct() { self::fail(0, __FUNCTION__); parent::__construct(array(1, 2)); self::fail(1, __FUNCTION__); } function rewind() { self::fail(2, __FUNCTION__); return parent::rewind(); } function valid() { self::fail(3, __FUNCTION__); return parent::valid(); } function key() { self::fail(4, __FUNCTION__); return parent::key(); } function current() { self::fail(5, __FUNCTION__); return parent::current(); } function next() { self::fail(6, __FUNCTION__); return parent::next(); } function __destruct() { self::fail(7, __FUNCTION__); } static function test() { self::$fail = 0; while(self::$fail < 10) { echo '===' . self::$fail . "===\n"; try { var_dump(iterator_to_array(new MyArrayIterator())); break; } catch (Exception $e) { var_dump($e->getMessage()); } self::$fail++; } self::$fail = 0; while(self::$fail < 10) { echo '===' . self::$fail . "===\n"; try { var_dump(iterator_count(new MyArrayIterator())); break; } catch (Exception $e) { var_dump($e->getMessage()); } if (self::$fail == 3) { self::$fail = 6; } else { self::$fail++; } } } } MyArrayIterator::test(); ?> ===DONE=== <?php exit(0); ?> --EXPECT-- ===0=== string(22) "State 0: __construct()" ===1=== string(22) "State 1: __construct()" ===2=== string(17) "State 2: rewind()" ===3=== string(16) "State 3: valid()" ===4=== string(14) "State 4: key()" ===5=== string(18) "State 5: current()" ===6=== string(15) "State 6: next()" ===7=== string(21) "State 7: __destruct()" ===8=== array(2) { [0]=> int(1) [1]=> int(2) } ===0=== string(22) "State 0: __construct()" ===1=== string(22) "State 1: __construct()" ===2=== string(17) "State 2: rewind()" ===3=== string(16) "State 3: valid()" ===4=== string(15) "State 6: next()" ===7=== string(21) "State 7: __destruct()" ===8=== int(2) ===DONE=== http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_041a.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/iterator_041a.phpt +++ php-src/ext/spl/tests/iterator_041a.phpt --TEST-- SPL: iterator_to_array() and exceptions from destruct --SKIPIF-- <?php if (!extension_loaded("spl")) print "skip"; ?> --FILE-- <?php class MyArrayIterator extends ArrayIterator { static protected $fail = 0; public $state; static function fail($state, $method) { if (self::$fail == $state) { throw new Exception("State $state: $method()"); } } function __construct() { $this->state = MyArrayIterator::$fail; self::fail(0, __FUNCTION__); parent::__construct(array(1, 2)); self::fail(1, __FUNCTION__); } function rewind() { self::fail(2, __FUNCTION__); return parent::rewind(); } function valid() { self::fail(3, __FUNCTION__); return parent::valid(); } function current() { self::fail(4, __FUNCTION__); return parent::current(); } function key() { self::fail(5, __FUNCTION__); return parent::key(); } function next() { self::fail(6, __FUNCTION__); return parent::next(); } function __destruct() { self::fail(7, __FUNCTION__); } static function test($func, $skip = null) { echo "===$func===\n"; self::$fail = 7; while(self::$fail < 10) { try { var_dump($func(new MyArrayIterator())); break; } catch (Exception $e) { echo $e->getMessage() . "\n"; } if (isset($skip[self::$fail])) { self::$fail = $skip[self::$fail]; } else { self::$fail++; } } } } MyArrayIterator::test('iterator_to_array'); MyArrayIterator::test('iterator_count', array(3 => 6)); ?> ===DONE=== <?php exit(0); ?> --EXPECT-- ===iterator_to_array=== State 7: __destruct() array(2) { [0]=> int(1) [1]=> int(2) } ===iterator_count=== State 7: __destruct() int(2) ===DONE=== http://cvs.php.net/viewcvs.cgi/php-src/ext/spl/tests/iterator_041b.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/iterator_041b.phpt +++ php-src/ext/spl/tests/iterator_041b.phpt --TEST-- SPL: iterator_to_array() and exceptions from delayed destruct --SKIPIF-- <?php if (!extension_loaded("spl")) print "skip"; ?> --FILE-- <?php class MyArrayIterator extends ArrayIterator { static protected $fail = 0; public $state; static function fail($state, $method) { if (self::$fail == $state) { throw new Exception("State $state: $method()"); } } function __construct() { $this->state = MyArrayIterator::$fail; self::fail(0, __FUNCTION__); parent::__construct(array(1, 2)); self::fail(1, __FUNCTION__); } function rewind() { self::fail(2, __FUNCTION__); return parent::rewind(); } function valid() { self::fail(3, __FUNCTION__); return parent::valid(); } function current() { self::fail(4, __FUNCTION__); return parent::current(); } function key() { self::fail(5, __FUNCTION__); return parent::key(); } function next() { self::fail(6, __FUNCTION__); return parent::next(); } function __destruct() { self::fail(7, __FUNCTION__); } static function test($func, $skip = null) { echo "===$func===\n"; self::$fail = 0; while(self::$fail < 10) { try { var_dump($func(new MyArrayIterator())); break; } catch (Exception $e) { echo $e->getMessage() . "\n"; } if (isset($skip[self::$fail])) { self::$fail = $skip[self::$fail]; } else { self::$fail++; } } } } MyArrayIterator::test('iterator_to_array'); MyArrayIterator::test('iterator_count', array(3 => 6)); ?> ===DONE=== <?php exit(0); ?> --EXPECT-- ===iterator_to_array=== State 0: __construct() State 1: __construct() State 2: rewind() State 3: valid() State 4: current() State 5: key() State 6: next() Fatal error: Ignoring exception from MyArrayIterator::__destruct() while an exception is already active (Uncaught Exception in /usr/src/php-cvs/ext/spl/tests/iterator_041b.phpt on line 17) in %siterator_041b.php on line %d
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php