helly           Sat Jul 19 21:22:04 2003 EDT

  Added files:                 
    /spl/tests  array_iterator.phpt 

  Modified files:              
    /spl        spl_array.c 
  Log:
  - Add class spl_array_it which is the iterator returned by spl_array.
    This class can also be used alone without spl_array but doesn't allow
    recursive foreach usage.
  - Fix protos to new proto system.
  - Add test for spl_array_it.
  
  
Index: spl/spl_array.c
diff -u spl/spl_array.c:1.9 spl/spl_array.c:1.10
--- spl/spl_array.c:1.9 Sat Jul 19 16:54:22 2003
+++ spl/spl_array.c     Sat Jul 19 21:22:03 2003
@@ -241,6 +241,7 @@
 /* }}} */
 
 SPL_CLASS_FUNCTION(array, __construct);
+SPL_CLASS_FUNCTION(array, new_iterator);
 SPL_CLASS_FUNCTION(array, rewind);
 SPL_CLASS_FUNCTION(array, current);
 SPL_CLASS_FUNCTION(array, key);
@@ -249,6 +250,12 @@
 
 static zend_function_entry spl_array_class_functions[] = {
        SPL_CLASS_FE(array, __construct,   NULL)
+       SPL_CLASS_FE(array, new_iterator,  NULL)
+       {NULL, NULL, NULL}
+};
+
+static zend_function_entry spl_array_it_class_functions[] = {
+       SPL_CLASS_FE(array, __construct,   NULL)
        SPL_CLASS_FE(array, rewind,        NULL)
        SPL_CLASS_FE(array, current,       NULL)
        SPL_CLASS_FE(array, key,           NULL)
@@ -258,7 +265,10 @@
 };
 
 static zend_object_handlers spl_array_handlers;
-static zend_class_entry *spl_ce_array;
+static zend_class_entry *   spl_ce_array;
+
+static zend_object_handlers spl_array_it_handlers;
+static zend_class_entry *   spl_ce_array_it;
 
 typedef struct _spl_array_object {
        zend_object       std;
@@ -309,7 +319,11 @@
        zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
 
        retval.handle = zend_objects_store_put(intern, spl_array_object_dtor, NULL 
TSRMLS_CC);
-       retval.handlers = &spl_array_handlers;
+       if (class_type == spl_ce_array_it) {
+               retval.handlers = &spl_array_it_handlers;
+       } else {
+               retval.handlers = &spl_array_handlers;
+       }
        return retval;
 }
 /* }}} */
@@ -348,6 +362,13 @@
 }
 /* }}} */
 
+/* {{{ spl_array_get_ce */
+static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC)
+{
+       return spl_ce_array_it;
+}
+/* }}} */
+
 /* {{{ spl_array_read_dimension */
 zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC)
 {
@@ -434,7 +455,7 @@
 PHP_MINIT_FUNCTION(spl_array)
 {
        REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, 
spl_array_class_functions);
-       REGISTER_SPL_IMPLEMENT(array, sequence_assoc);
+       REGISTER_SPL_IMPLEMENT(array, iterator);
        memcpy(&spl_array_handlers, zend_get_std_object_handlers(), 
sizeof(zend_object_handlers));
        spl_array_handlers.clone_obj = spl_array_object_clone;
        spl_array_handlers.get_class_entry = spl_array_get_ce;
@@ -442,11 +463,17 @@
        spl_array_handlers.write_dimension = spl_array_write_dimension;
        spl_array_handlers.get_properties = spl_array_get_properties;
 
+       REGISTER_SPL_STD_CLASS_EX(array_it, spl_array_object_new, 
spl_array_it_class_functions);
+       REGISTER_SPL_IMPLEMENT(array_it, sequence_assoc);
+       memcpy(&spl_array_it_handlers, &spl_array_handlers, 
sizeof(zend_object_handlers));
+       spl_array_it_handlers.get_class_entry = spl_array_it_get_ce;
+
        return SUCCESS;
 }
 /* }}} */
 
-/* {{{ proto void __construct(array ar = array())
+/* {{{ proto void spl_array::__construct(array ar = array())
+       proto void spl_array_it::__construct(array ar = array())
  Cronstructs a new array iterator from a path. */
 SPL_CLASS_FUNCTION(array, __construct)
 {
@@ -480,26 +507,86 @@
 }
 /* }}} */
 
-/* {{{ proto void rewind()
+/* {{{ proto spl_array_it|NULL spl_array::new_iterator()
+   Create a new iterator from a spl_array instance */
+SPL_CLASS_FUNCTION(array, new_iterator)
+{
+       zval *object = getThis();
+       spl_array_object *intern = 
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+       spl_array_object *iterator;
+       HashTable *aht = HASH_OF(intern->array);
+
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
+
+       return_value->type = IS_OBJECT;
+       return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, 
intern TSRMLS_CC);
+       return_value->refcount = 1;
+       return_value->is_ref = 1;
+}
+/* }}} */
+
+/* {{{ spl_hash_pos_exists */
+ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC)
+{
+       HashTable *ht = HASH_OF(intern->array);
+       Bucket *p;
+
+/*     IS_CONSISTENT(ht);*/
+
+/*     HASH_PROTECT_RECURSION(ht);*/
+       p = ht->pListHead;
+       while (p != NULL) {
+               if (p == intern->pos) {
+                       return SUCCESS;
+               }
+               p = p->pListNext;
+       }
+/*     HASH_UNPROTECT_RECURSION(ht); */
+       zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
+       return FAILURE;
+}
+/* }}} */
+
+/* {{{ proto void spl_array_it::rewind()
    Rewind array back to the start */
 SPL_CLASS_FUNCTION(array, rewind)
 {
        zval *object = getThis();
        spl_array_object *intern = 
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+       HashTable *aht = HASH_OF(intern->array);
 
-       zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos);
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
+
+       zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
 }
 /* }}} */
 
-/* {{{ proto string current()
+/* {{{ proto mixed|false spl_array_it::current()
    Return current array entry */
 SPL_CLASS_FUNCTION(array, current)
 {
        zval *object = getThis();
        spl_array_object *intern = 
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
        zval **entry;
+       HashTable *aht = HASH_OF(intern->array);
 
-       if (zend_hash_get_current_data_ex(HASH_OF(intern->array), (void **) &entry, 
&intern->pos) == FAILURE) {
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
+
+       if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) 
{
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and internal position is no longer valid");
+               RETURN_FALSE;
+       }
+
+       if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == 
FAILURE) {
                RETURN_FALSE;
        }
        *return_value = **entry;
@@ -507,7 +594,7 @@
 }
 /* }}} */
 
-/* {{{ proto string key()
+/* {{{ proto mixed|false spl_array_it::key()
    Return current array key */
 SPL_CLASS_FUNCTION(array, key)
 {
@@ -516,8 +603,19 @@
        char *string_key;
        uint string_length;
        ulong num_key;
+       HashTable *aht = HASH_OF(intern->array);
+
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
 
-       switch (zend_hash_get_current_key_ex(HASH_OF(intern->array), &string_key, 
&string_length, &num_key, 0, &intern->pos)) {
+       if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) 
{
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and internal position is no longer valid");
+               RETURN_FALSE;
+       }
+
+       switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, 
&num_key, 0, &intern->pos)) {
                case HASH_KEY_IS_STRING:
                        RETVAL_STRINGL(string_key, string_length - 1, 1);
                        break;
@@ -530,25 +628,46 @@
 }
 /* }}} */
 
-/* {{{ proto void next()
+/* {{{ proto void spl_array_it::next()
    Move to next entry */
 SPL_CLASS_FUNCTION(array, next)
 {
        zval *object = getThis();
        spl_array_object *intern = 
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+       HashTable *aht = HASH_OF(intern->array);
 
-       zend_hash_move_forward_ex(HASH_OF(intern->array), &intern->pos);
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
+
+       if (intern->array->is_ref && spl_hash_pos_exists(intern TSRMLS_CC) == FAILURE) 
{
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and internal position is no longer valid");
+       } else {
+               zend_hash_move_forward_ex(aht, &intern->pos);
+       }
 }
 /* }}} */
 
-/* {{{ proto string has_more()
+/* {{{ proto bool spl_array_it::has_more()
    Check whether array contains more entries */
 SPL_CLASS_FUNCTION(array, has_more)
 {
        zval *object = getThis();
        spl_array_object *intern = 
(spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
+       HashTable *aht = HASH_OF(intern->array);
+
+       if (!aht) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and is no longer an array");
+               return;
+       }
 
-       RETURN_BOOL(zend_hash_has_more_elements_ex(HASH_OF(intern->array), 
&intern->pos) == SUCCESS);
+       if (intern->pos && intern->array->is_ref && spl_hash_pos_exists(intern 
TSRMLS_CC) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside 
object and internal position is no longer valid");
+               RETURN_FALSE;
+       } else {
+               RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == 
SUCCESS);
+       }
 }
 /* }}} */
 

Index: spl/tests/array_iterator.phpt
+++ spl/tests/array_iterator.phpt
--TEST--
SPL: spl_array_iterator
--SKIPIF--
<?php if (!extension_loaded("spl")) print "skip"; ?>
--FILE--
<?php

echo "==Normal==\n";

$arr = array(0=>0, 1=>1, 2=>2);
$obj = new spl_array($arr);

foreach($obj as $ak=>$av) {
        foreach($obj as $bk=>$bv) {
                if ($ak==0 && $bk==0) {
                        $arr[0] = "modify";
                }
                echo "$ak=>$av - $bk=>$bv\n";
        }
}

echo "==UseRef==\n";

$arr = array(0=>0, 1=>1, 2=>2);
$obj = new spl_array(&$arr);

foreach($obj as $ak=>$av) {
        foreach($obj as $bk=>$bv) {
                echo "$ak=>$av - $bk=>$bv\n";
        }
}

echo "==Modify==\n";

$arr = array(0=>0, 1=>1, 2=>2);
$obj = new spl_array(&$arr);

foreach($obj as $ak=>$av) {
        foreach($obj as $bk=>$bv) {
                if ($ak==0 && $bk==0) {
                        $arr[0] = "modify";
                }
                echo "$ak=>$av - $bk=>$bv\n";
        }
}

echo "==Delete==\n";

$arr = array(0=>0, 1=>1, 2=>2);
$obj = new spl_array(&$arr);

foreach($obj as $ak=>$av) {
        foreach($obj as $bk=>$bv) {
                if ($ak==1 && $bk==1) {
                        unset($arr[1]);
                }
                echo "$ak=>$av - $bk=>$bv\n";
        }
}

echo "==Change==\n";

$arr = array(0=>0, 1=>1, 2=>2);
$obj = new spl_array(&$arr);

foreach($obj as $ak=>$av) {
        foreach($obj as $bk=>$bv) {
                if ($ak==1 && $bk==1) {
                        $arr = NULL;
                }
                echo "$ak=>$av - $bk=>$bv\n";
        }
}

echo "Done\n";
?>
--EXPECTF--
==Normal==
0=>0 - 0=>0
0=>0 - 1=>1
0=>0 - 2=>2
1=>1 - 0=>0
1=>1 - 1=>1
1=>1 - 2=>2
2=>2 - 0=>0
2=>2 - 1=>1
2=>2 - 2=>2
==UseRef==
0=>0 - 0=>0
0=>0 - 1=>1
0=>0 - 2=>2
1=>1 - 0=>0
1=>1 - 1=>1
1=>1 - 2=>2
2=>2 - 0=>0
2=>2 - 1=>1
2=>2 - 2=>2
==Modify==
0=>0 - 0=>0
0=>0 - 1=>1
0=>0 - 2=>2
1=>1 - 0=>modify
1=>1 - 1=>1
1=>1 - 2=>2
2=>2 - 0=>modify
2=>2 - 1=>1
2=>2 - 2=>2
==Delete==
0=>0 - 0=>0
0=>0 - 1=>1
0=>0 - 2=>2
1=>1 - 0=>0
1=>1 - 1=>1

Notice: next(): Array was modified outside object and internal position is no longer 
valid in %sarray_iterator.php on line %d
1=>1 - 0=>0
1=>1 - 2=>2

Notice: next(): Array was modified outside object and internal position is no longer 
valid in %sarray_iterator.php on line %d
0=>0 - 0=>0
0=>0 - 2=>2
2=>2 - 0=>0
2=>2 - 2=>2
==Change==
0=>0 - 0=>0
0=>0 - 1=>1
0=>0 - 2=>2
1=>1 - 0=>0
1=>1 - 1=>1

Notice: next(): Array was modified outside object and is no longer an array in 
%sarray_iterator.php on line %d

Notice: has_more(): Array was modified outside object and is no longer an array in 
%sarray_iterator.php on line %d

Notice: next(): Array was modified outside object and is no longer an array in 
%sarray_iterator.php on line %d

Notice: has_more(): Array was modified outside object and is no longer an array in 
%sarray_iterator.php on line %d
Done

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to