Index: spl_array.c =================================================================== RCS file: /repository/php-src/ext/spl/spl_array.c,v retrieving revision 1.71.2.17.2.13.2.19 diff -u -w -p -r1.71.2.17.2.13.2.19 spl_array.c --- spl_array.c 26 Jul 2008 12:34:10 -0000 1.71.2.17.2.13.2.19 +++ spl_array.c 3 Aug 2008 09:59:32 -0000 @@ -924,50 +924,16 @@ zend_object_iterator *spl_array_get_iter } /* }}} */ -/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]) - proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0]) - Cronstructs a new array iterator from a path. */ -SPL_METHOD(Array, __construct) -{ - zval *object = getThis(); - spl_array_object *intern; - zval **array; - long ar_flags = 0; - char *class_name; - int class_name_len; - zend_class_entry ** pce_get_iterator; - - if (ZEND_NUM_ARGS() == 0) { - return; /* nothing to do */ - } - php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC); - - intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ls", &array, &ar_flags, &class_name, &class_name_len) == FAILURE) { - php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); - return; - } +/* {{{ spl_array_set_array */ +static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) { if (Z_TYPE_PP(array) == IS_ARRAY) { SEPARATE_ZVAL_IF_NOT_REF(array); } - if (ZEND_NUM_ARGS() > 2) { - if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) { - zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC); - php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); - return; - } - intern->ce_get_iterator = *pce_get_iterator; - } - - ar_flags &= ~SPL_ARRAY_INT_MASK; - if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) { zval_ptr_dtor(&intern->array); - if (ZEND_NUM_ARGS() == 1) - { + if (just_array) { spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC); ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK; } @@ -996,9 +962,50 @@ SPL_METHOD(Array, __construct) || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) { php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name); + } + } + + spl_array_rewind(intern TSRMLS_CC); +} +/* }}} */ + +/* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]]) + proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0]) + Cronstructs a new array iterator from a path. */ +SPL_METHOD(Array, __construct) +{ + zval *object = getThis(); + spl_array_object *intern; + zval **array; + long ar_flags = 0; + char *class_name; + int class_name_len; + zend_class_entry ** pce_get_iterator; + + if (ZEND_NUM_ARGS() == 0) { + return; /* nothing to do */ + } + php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC); + + intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ls", &array, &ar_flags, &class_name, &class_name_len) == FAILURE) { + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); return; } + + if (ZEND_NUM_ARGS() > 2) { + if (zend_lookup_class(class_name, class_name_len, &pce_get_iterator TSRMLS_CC) == FAILURE) { + zend_throw_exception(spl_ce_InvalidArgumentException, "A class that implements Iterator must be specified", 0 TSRMLS_CC); + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + return; } + intern->ce_get_iterator = *pce_get_iterator; + } + + ar_flags &= ~SPL_ARRAY_INT_MASK; + + spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC); spl_array_rewind(intern TSRMLS_CC); @@ -1081,31 +1088,9 @@ SPL_METHOD(Array, exchangeArray) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) { return; } - 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; - } 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); - return; - } - zval_ptr_dtor(&intern->array); - intern->array = *array; - intern->ar_flags &= ~SPL_ARRAY_USE_OTHER; - } - if (object == *array) { - intern->ar_flags |= SPL_ARRAY_IS_SELF; - } else { - intern->ar_flags &= ~SPL_ARRAY_IS_SELF; - } - Z_ADDREF_P(intern->array); - spl_array_rewind(intern TSRMLS_CC); + spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC); + } /* }}} */ Index: tests/arrayObject_exchange_basic1.phpt =================================================================== RCS file: tests/arrayObject_exchange_basic1.phpt diff -N tests/arrayObject_exchange_basic1.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/arrayObject_exchange_basic1.phpt 3 Aug 2008 09:44:39 -0000 @@ -0,0 +1,40 @@ +--TEST-- +ArrayObject::exchange() and copy-on-write references +--FILE-- +exchangeArray($swapIn); + +$ao['a'] = 'adding element to $ao'; +$swapIn['b'] = 'adding element to $swapIn'; +$ao['c'] = 'adding another element to $ao'; + +echo "\n--> swapIn: "; +var_dump($swapIn); + +echo "\n--> cowRef: "; +var_dump($cowRef); + +echo "\n--> ao: "; +var_dump($ao); +?> +--EXPECTF-- +--> swapIn: array(1) { + ["b"]=> + string(25) "adding element to $swapIn" +} + +--> cowRef: array(0) { +} + +--> ao: object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(2) { + ["a"]=> + string(21) "adding element to $ao" + ["c"]=> + string(29) "adding another element to $ao" + } +} Index: tests/arrayObject_exchange_basic2.phpt =================================================================== RCS file: tests/arrayObject_exchange_basic2.phpt diff -N tests/arrayObject_exchange_basic2.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/arrayObject_exchange_basic2.phpt 3 Aug 2008 09:48:20 -0000 @@ -0,0 +1,33 @@ +--TEST-- +ArrayObject::exchangeArray(object) +--FILE-- + exchangeArray(array):\n"; +$ao = new ArrayObject(); +$ao->exchangeArray(array('original')); +var_dump($ao); + +echo "\n--> exchangeArray(object):\n"; +$obj = new stdClass; +$obj->newProp = 'changed'; +$ao->exchangeArray($obj); +var_dump($ao); +?> +--EXPECTF-- +--> exchangeArray(array): +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + array(1) { + [0]=> + string(8) "original" + } +} + +--> exchangeArray(object): +object(ArrayObject)#%d (1) { + ["storage":"ArrayObject":private]=> + object(stdClass)#%d (1) { + ["newProp"]=> + string(7) "changed" + } +} \ No newline at end of file