]> granicus.if.org Git - php/commitdiff
- Fix handling of ArrayObject/ArrayIterator flags and provide test
authorMarcus Boerger <helly@php.net>
Mon, 20 Jun 2005 00:19:18 +0000 (00:19 +0000)
committerMarcus Boerger <helly@php.net>
Mon, 20 Jun 2005 00:19:18 +0000 (00:19 +0000)
ext/spl/spl_array.c
ext/spl/tests/array_017.phpt [new file with mode: 0755]

index 2449f596719d486429dd079ed41b32dc5e02b947..84fafa011788e1d2602f8db84148da058ac8d236 100755 (executable)
@@ -145,6 +145,7 @@ PHPAPI zend_class_entry  *spl_ce_Countable;
 #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
 #define SPL_ARRAY_IS_REF         0x01000000
 #define SPL_ARRAY_IS_SELF        0x02000000
+#define SPL_ARRAY_USE_OTHER      0x04000000
 #define SPL_ARRAY_INT_MASK       0xFF000000
 #define SPL_ARRAY_CLONE_MASK     0x03000003
 
@@ -160,8 +161,11 @@ typedef struct _spl_array_object {
        zend_function *   fptr_offset_del;
 } spl_array_object;
 
-static inline HashTable *spl_array_get_hash_table(spl_array_object* intern TSRMLS_DC) {
-       if ((intern->ar_flags & (SPL_ARRAY_STD_PROP_LIST|SPL_ARRAY_IS_SELF)) != 0) {
+static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) {
+       if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0)) {
+               spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
+               return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
+       } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
                return intern->std.properties;
        } else {
                return HASH_OF(intern->array);
@@ -170,7 +174,7 @@ static inline HashTable *spl_array_get_hash_table(spl_array_object* intern TSRML
 
 SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
 {
-       HashTable *ht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
        Bucket *p;
 
 /*     IS_CONSISTENT(ht);*/
@@ -184,7 +188,7 @@ SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
                p = p->pListNext;
        }
 /*     HASH_UNPROTECT_RECURSION(ht); */
-       zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern TSRMLS_CC), &intern->pos);
+       zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
        return FAILURE;
 }
 /* }}} */
@@ -204,7 +208,7 @@ static void spl_array_object_free_storage(void *object TSRMLS_DC)
 /* }}} */
 
 /* {{{ spl_array_object_new */
-static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, spl_array_object *orig TSRMLS_DC)
+static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig TSRMLS_DC)
 {
        zend_object_value retval;
        spl_array_object *intern;
@@ -223,10 +227,12 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s
 
        intern->ar_flags = 0;
        if (orig) {
-               intern->array = orig->array;
+               spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
+
+               intern->array = orig;
                ZVAL_ADDREF(intern->array);
                intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
-               intern->ar_flags |= (orig->ar_flags & SPL_ARRAY_CLONE_MASK) | SPL_ARRAY_IS_REF;
+               intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK) | SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
        } else {
                MAKE_STD_ZVAL(intern->array);
                array_init(intern->array);
@@ -266,7 +272,7 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s
                        intern->fptr_offset_del = NULL;
                }
        }
-       zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern TSRMLS_CC), &intern->pos);
+       zend_hash_internal_pointer_reset_ex(spl_array_get_hash_table(intern, 0 TSRMLS_CC), &intern->pos);
        return retval;
 }
 /* }}} */
@@ -289,7 +295,7 @@ static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
        spl_array_object *intern;
 
        old_object = zend_objects_get_address(zobject TSRMLS_CC);
-       new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, (spl_array_object*)old_object TSRMLS_CC);
+       new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject TSRMLS_CC);
        new_object = &intern->std;
 
        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
@@ -311,7 +317,7 @@ static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object,
        
        switch(Z_TYPE_P(offset)) {
        case IS_STRING:
-               if (zend_symtable_find(spl_array_get_hash_table(intern TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
+               if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
                        zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(offset));
                        return &EG(uninitialized_zval_ptr);
                } else {
@@ -326,7 +332,7 @@ static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object,
                } else {
                        index = Z_LVAL_P(offset);
                }
-               if (zend_hash_index_find(spl_array_get_hash_table(intern TSRMLS_CC), index, (void **) &retval) == FAILURE) {
+               if (zend_hash_index_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void **) &retval) == FAILURE) {
                        zend_error(E_NOTICE, "Undefined offset:  %ld", Z_LVAL_P(offset));
                        return &EG(uninitialized_zval_ptr);
                } else {
@@ -369,13 +375,13 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval
        
        if (!offset) {
                value->refcount++;
-               zend_hash_next_index_insert(spl_array_get_hash_table(intern TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
+               zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
                return;
        }
        switch(Z_TYPE_P(offset)) {
        case IS_STRING:
                value->refcount++;
-               zend_symtable_update(spl_array_get_hash_table(intern TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
+               zend_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
                return;
        case IS_DOUBLE:
        case IS_RESOURCE:
@@ -387,7 +393,7 @@ static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval
                        index = Z_LVAL_P(offset);
                }
                value->refcount++;
-               zend_hash_index_update(spl_array_get_hash_table(intern TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
+               zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
                return;
        default:
                zend_error(E_WARNING, "Illegal offset type");
@@ -413,12 +419,12 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval
 
        switch(Z_TYPE_P(offset)) {
        case IS_STRING:
-               if (spl_array_get_hash_table(intern TSRMLS_CC) == &EG(symbol_table)) {
+               if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
                        if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
                                zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
                        }
                } else {
-                       if (zend_symtable_del(spl_array_get_hash_table(intern TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
+                       if (zend_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
                                zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
                        }
                }
@@ -432,7 +438,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval
                } else {
                        index = Z_LVAL_P(offset);
                }
-               if (zend_hash_index_del(spl_array_get_hash_table(intern TSRMLS_CC), index) == FAILURE) {
+               if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
                        zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
                }
                break;
@@ -466,7 +472,7 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o
        
        switch(Z_TYPE_P(offset)) {
        case IS_STRING:
-               return zend_symtable_exists(spl_array_get_hash_table(intern TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
+               return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
        case IS_DOUBLE:
        case IS_RESOURCE:
        case IS_BOOL: 
@@ -476,7 +482,7 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o
                } else {
                        index = Z_LVAL_P(offset);
                }
-               return zend_hash_index_exists(spl_array_get_hash_table(intern TSRMLS_CC), index);
+               return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
        default:
                zend_error(E_WARNING, "Illegal offset type");
        }
@@ -529,7 +535,7 @@ SPL_METHOD(Array, offsetSet)
 void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
 {
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -580,14 +586,14 @@ SPL_METHOD(Array, getArrayCopy)
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     
     array_init(return_value);
-       zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
+       zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
 } /* }}} */
 
 static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
 {
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
 
-       return spl_array_get_hash_table(intern TSRMLS_CC);
+       return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
 } /* }}} */
 
 static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
@@ -657,7 +663,7 @@ static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ *
        char *string_key;
        uint string_length;
        ulong num_key;
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
                do {
@@ -680,7 +686,7 @@ static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ *
 
 static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
 {
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
@@ -715,7 +721,7 @@ static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
 {
        spl_array_it       *iterator = (spl_array_it *)iter;
        spl_array_object   *object   = iterator->object;
-       HashTable          *aht      = spl_array_get_hash_table(object TSRMLS_CC);
+       HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
@@ -735,7 +741,7 @@ static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***da
 {
        spl_array_it       *iterator = (spl_array_it *)iter;
        spl_array_object   *object   = iterator->object;
-       HashTable          *aht      = spl_array_get_hash_table(object TSRMLS_CC);
+       HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
        
        if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
                *data = NULL;
@@ -747,7 +753,7 @@ static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_k
 {
        spl_array_it       *iterator = (spl_array_it *)iter;
        spl_array_object   *object   = iterator->object;
-       HashTable          *aht      = spl_array_get_hash_table(object TSRMLS_CC);
+       HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
@@ -768,7 +774,7 @@ static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {
        spl_array_it       *iterator = (spl_array_it *)iter;
        spl_array_object   *object   = iterator->object;
 
-       HashTable          *aht      = spl_array_get_hash_table(object TSRMLS_CC);
+       HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
@@ -785,7 +791,7 @@ static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {
 
 static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
 {
-       HashTable          *aht      = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
@@ -852,10 +858,17 @@ SPL_METHOD(Array, __construct)
                return;
        }
 
+       ar_flags &= ~SPL_ARRAY_INT_MASK;
+
        if (Z_TYPE_P(array) == IS_OBJECT && (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject || Z_OBJ_HT_P(array) == &spl_handler_ArrayIterator)) {
-               spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(array TSRMLS_CC);
                zval_ptr_dtor(&intern->array);
-               intern->array = other->array;           
+               if (ZEND_NUM_ARGS() == 1)
+               {
+                       spl_array_object *other = (spl_array_object*)zend_object_store_get_object(array TSRMLS_CC);
+                       ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
+               }               
+               ar_flags |= SPL_ARRAY_USE_OTHER;
+               intern->array = array;
        } else {
                if (Z_TYPE_P(array) != IS_OBJECT && Z_TYPE_P(array) != IS_ARRAY) {
                        php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
@@ -870,7 +883,7 @@ SPL_METHOD(Array, __construct)
        } else {
                intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
        }
-       intern->ar_flags |= ar_flags & ~SPL_ARRAY_INT_MASK;
+       intern->ar_flags |= ar_flags;
        ZVAL_ADDREF(intern->array);
 
        spl_array_rewind(intern TSRMLS_CC);
@@ -914,15 +927,20 @@ SPL_METHOD(Array, exchangeArray)
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     
     array_init(return_value);
-       zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
+       zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
        
        if (ZEND_NUM_ARGS() > 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
                WRONG_PARAM_COUNT;
        }
-       if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
+       if (Z_TYPE_PP(array) == IS_OBJECT && intern == (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC))
+       {
+               zval_ptr_dtor(&intern->array);
+               array = &object;
+               intern->array = object;
+       } else if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
                spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
                zval_ptr_dtor(&intern->array);
-               intern->array = other->array;           
+               intern->array = other->array;
        } else {
                if (Z_TYPE_PP(array) != IS_OBJECT && !HASH_OF(*array)) {
                        zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
@@ -949,7 +967,7 @@ SPL_METHOD(Array, getIterator)
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
        spl_array_object *iterator;
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -957,7 +975,7 @@ SPL_METHOD(Array, getIterator)
        }
 
        return_value->type = IS_OBJECT;
-       return_value->value.obj = spl_array_object_new_ex(spl_ce_ArrayIterator, &iterator, intern TSRMLS_CC);
+       return_value->value.obj = spl_array_object_new_ex(spl_ce_ArrayIterator, &iterator, object TSRMLS_CC);
        return_value->refcount = 1;
        return_value->is_ref = 1;
 }
@@ -981,7 +999,7 @@ SPL_METHOD(Array, seek)
        long opos, position;
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
        int result;
 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
@@ -1014,7 +1032,7 @@ SPL_METHOD(Array, seek)
 int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
 {
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
        HashPosition pos;
 
        if (!aht) {
@@ -1058,7 +1076,7 @@ SPL_METHOD(Array, current)
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
        zval **entry;
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -1086,7 +1104,7 @@ SPL_METHOD(Array, key)
        char *string_key;
        uint string_length;
        ulong num_key;
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -1117,7 +1135,7 @@ SPL_METHOD(Array, next)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
@@ -1134,7 +1152,7 @@ SPL_METHOD(Array, valid)
 {
        zval *object = getThis();
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
-       HashTable *aht = spl_array_get_hash_table(intern TSRMLS_CC);
+       HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
 
        if (!aht) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
diff --git a/ext/spl/tests/array_017.phpt b/ext/spl/tests/array_017.phpt
new file mode 100755 (executable)
index 0000000..f028a12
--- /dev/null
@@ -0,0 +1,649 @@
+--TEST--
+SPL: ArrayObject::exchangeArray($this)
+--SKIPIF--
+<?php if (!extension_loaded("spl")) print "skip"; ?>
+--FILE--
+<?php
+
+class ArrayIteratorEx extends ArrayIterator
+{
+       public    $pub2 = 1;
+       protected $pro2 = 2;
+       private   $pri2 = 3;
+
+       function __construct($ar, $flags = 0)
+       {
+               echo __METHOD__ . "()\n";
+               parent::__construct($ar, $flags);
+               $this->imp2 = 4;
+       }
+
+       function dump()
+       {
+               echo __METHOD__ . "()\n";
+               var_dump(array('Flags'=>$this->getFlags()
+                             ,'OVars'=>get_object_vars($this)
+                             ,'$this'=>$this));
+       }
+
+       function setFlags($flags)
+       {
+               echo __METHOD__ . "($flags)\n";
+               ArrayObject::setFlags($flags);
+       }
+}
+
+class ArrayObjectEx extends ArrayObject
+{
+       public    $pub1 = 1;
+       protected $pro1 = 2;
+       private   $pri1 = 3;
+       
+       function __construct($ar = array(), $flags = 0)
+       {
+               echo __METHOD__ . "()\n";
+               parent::__construct($ar, $flags);
+               $this->imp1 = 4;
+       }
+
+       function exchange()
+       {
+               echo __METHOD__ . "()\n";
+               $this->exchangeArray($this);
+       }
+
+       function dump()
+       {
+               echo __METHOD__ . "()\n";
+               var_dump(array('Flags'=>$this->getFlags()
+                             ,'OVars'=>get_object_vars($this)
+                             ,'$this'=>$this));
+       }
+
+       function show()
+       {
+               echo __METHOD__ . "()\n";
+               foreach($this as $n => $v)
+               {
+                       var_dump(array($n => $v));
+               }
+       }
+       
+       function setFlags($flags)
+       {
+               echo __METHOD__ . "($flags)\n";
+               ArrayObject::setFlags($flags);
+       }
+       
+       function getIterator()
+       {
+               echo __METHOD__ . "()\n";
+               $it = new ArrayIteratorEx($this, $this->getFlags());
+               $it->dyn2 = 5;
+               $it->dump();
+               return $it;
+       }
+}
+
+function check($obj, $flags)
+{
+       echo "===CHECK===\n";
+
+       $obj->setFlags($flags);
+       $obj->dump();
+       $obj->show();
+
+       echo "===FOREACH===\n";
+       
+       $it = $obj->getIterator();
+       foreach($it as $n => $v)
+       {
+               var_dump(array($n => $v));
+       }
+       
+       echo "===PROPERTY===\n";
+       
+       var_dump($obj->pub1);
+       var_dump(isset($obj->a));
+       $obj->setFlags($flags | 2);
+       var_dump($obj->pub1);
+       var_dump(isset($obj->a));
+       
+       var_dump($it->pub2);
+       var_dump(isset($it->pub1));
+       $it->setFlags($flags | 2);
+       var_dump($it->pub2);
+       var_dump(isset($it->pub1));
+}
+
+$obj = new ArrayObjectEx(array(0=>1,'a'=>25, 'pub1'=>42), 0);
+$obj->dyn1 = 5;
+
+check($obj, 0);
+check($obj, 1);
+
+echo "#####EXCHANGE#####\n";
+
+$obj->exchange();
+
+check($obj, 0);
+check($obj, 1);
+
+?>
+===DONE===
+<?php exit(0); ?>
+--EXPECTF--
+ArrayObjectEx::__construct()
+===CHECK===
+ArrayObjectEx::setFlags(0)
+ArrayObjectEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(2) {
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+  ["$this"]=>
+  object(ArrayObjectEx)#1 (3) {
+    [0]=>
+    int(1)
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(2) {
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#2 (3) {
+    [0]=>
+    int(1)
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+}
+array(1) {
+  [0]=>
+  int(1)
+}
+array(1) {
+  ["a"]=>
+  int(25)
+}
+array(1) {
+  ["pub1"]=>
+  int(42)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(2) {
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#3 (3) {
+    [0]=>
+    int(1)
+    ["a"]=>
+    int(25)
+    ["pub1"]=>
+    int(42)
+  }
+}
+array(1) {
+  [0]=>
+  int(1)
+}
+array(1) {
+  ["a"]=>
+  int(25)
+}
+array(1) {
+  ["pub1"]=>
+  int(42)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(2)
+int(1)
+bool(true)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(2)
+int(1)
+bool(true)
+===CHECK===
+ArrayObjectEx::setFlags(1)
+ArrayObjectEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1"]=>
+    int(2)
+    ["pri1"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayObjectEx)#1 (5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1:protected"]=>
+    int(2)
+    ["pri1:private"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2"]=>
+    int(2)
+    ["pri2"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#3 (5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2:protected"]=>
+    int(2)
+    ["pri2:private"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+}
+array(1) {
+  [0]=>
+  int(1)
+}
+array(1) {
+  ["a"]=>
+  int(25)
+}
+array(1) {
+  ["pub1"]=>
+  int(42)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2"]=>
+    int(2)
+    ["pri2"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#2 (5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2:protected"]=>
+    int(2)
+    ["pri2:private"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+}
+array(1) {
+  [0]=>
+  int(1)
+}
+array(1) {
+  ["a"]=>
+  int(25)
+}
+array(1) {
+  ["pub1"]=>
+  int(42)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(3)
+int(1)
+bool(true)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(3)
+int(1)
+bool(true)
+#####EXCHANGE#####
+ArrayObjectEx::exchange()
+===CHECK===
+ArrayObjectEx::setFlags(0)
+ArrayObjectEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1"]=>
+    int(2)
+    ["pri1"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayObjectEx)#1 (5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1:protected"]=>
+    int(2)
+    ["pri1:private"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(4) {
+    ["pub1"]=>
+    int(1)
+    ["pro1"]=>
+    int(2)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#2 (5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1:protected"]=>
+    int(2)
+    ["pri1:private"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+}
+array(1) {
+  ["pub1"]=>
+  int(1)
+}
+array(1) {
+  ["imp1"]=>
+  int(4)
+}
+array(1) {
+  ["dyn1"]=>
+  int(5)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(0)
+  ["OVars"]=>
+  array(4) {
+    ["pub1"]=>
+    int(1)
+    ["pro1"]=>
+    int(2)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#3 (5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1:protected"]=>
+    int(2)
+    ["pri1:private"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+}
+array(1) {
+  ["pub1"]=>
+  int(1)
+}
+array(1) {
+  ["imp1"]=>
+  int(4)
+}
+array(1) {
+  ["dyn1"]=>
+  int(5)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(2)
+int(1)
+bool(false)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(2)
+int(1)
+bool(true)
+===CHECK===
+ArrayObjectEx::setFlags(1)
+ArrayObjectEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1"]=>
+    int(2)
+    ["pri1"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayObjectEx)#1 (5) {
+    ["pub1"]=>
+    int(1)
+    ["pro1:protected"]=>
+    int(2)
+    ["pri1:private"]=>
+    int(3)
+    ["imp1"]=>
+    int(4)
+    ["dyn1"]=>
+    int(5)
+  }
+}
+ArrayObjectEx::show()
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2"]=>
+    int(2)
+    ["pri2"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#3 (5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2:protected"]=>
+    int(2)
+    ["pri2:private"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+}
+array(1) {
+  ["pub1"]=>
+  int(1)
+}
+array(1) {
+  ["imp1"]=>
+  int(4)
+}
+array(1) {
+  ["dyn1"]=>
+  int(5)
+}
+===FOREACH===
+ArrayObjectEx::getIterator()
+ArrayIteratorEx::__construct()
+ArrayIteratorEx::dump()
+array(3) {
+  ["Flags"]=>
+  int(1)
+  ["OVars"]=>
+  array(5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2"]=>
+    int(2)
+    ["pri2"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+  ["$this"]=>
+  object(ArrayIteratorEx)#2 (5) {
+    ["pub2"]=>
+    int(1)
+    ["pro2:protected"]=>
+    int(2)
+    ["pri2:private"]=>
+    int(3)
+    ["imp2"]=>
+    int(4)
+    ["dyn2"]=>
+    int(5)
+  }
+}
+array(1) {
+  ["pub1"]=>
+  int(1)
+}
+array(1) {
+  ["imp1"]=>
+  int(4)
+}
+array(1) {
+  ["dyn1"]=>
+  int(5)
+}
+===PROPERTY===
+int(1)
+bool(false)
+ArrayObjectEx::setFlags(3)
+int(1)
+bool(false)
+int(1)
+bool(false)
+ArrayIteratorEx::setFlags(3)
+int(1)
+bool(true)
+===DONE===