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

Reply via email to