robinf Mon Aug 4 11:45:15 2008 UTC Added files: /php-src/ext/spl/tests arrayObject_exchangeArray_basic1.phpt arrayObject_exchangeArray_basic2.phpt
Modified files: /php-src/ext/spl spl_array.c Log: Improve ArrayObject::exchangeArray() behaviour with objects and CoW references (see http://turl.ca/exarr ).
http://cvs.php.net/viewvc.cgi/php-src/ext/spl/spl_array.c?r1=1.144&r2=1.145&diff_format=u Index: php-src/ext/spl/spl_array.c diff -u php-src/ext/spl/spl_array.c:1.144 php-src/ext/spl/spl_array.c:1.145 --- php-src/ext/spl/spl_array.c:1.144 Sat Jul 26 12:33:34 2008 +++ php-src/ext/spl/spl_array.c Mon Aug 4 11:45:15 2008 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: spl_array.c,v 1.144 2008/07/26 12:33:34 lbarnaud Exp $ */ +/* $Id: spl_array.c,v 1.145 2008/08/04 11:45:15 robinf Exp $ */ #ifdef HAVE_CONFIG_H # include "config.h" @@ -899,6 +899,51 @@ } /* }}} */ +/* {{{ 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 (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 (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; + } + ar_flags |= SPL_ARRAY_USE_OTHER; + intern->array = *array; + } else { + if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) { + php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); + 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; + } + if (object == *array) { + intern->ar_flags |= SPL_ARRAY_IS_SELF; + intern->ar_flags &= ~SPL_ARRAY_USE_OTHER; + } else { + intern->ar_flags &= ~SPL_ARRAY_IS_SELF; + } + intern->ar_flags |= ar_flags; + Z_ADDREF_P(intern->array); + if (Z_TYPE_PP(array) == IS_OBJECT) { + zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties); + if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties) + || !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 %v is not compatible with %v", Z_OBJCE_PP(array)->name, intern->std.ce->name); + } + } + + spl_array_rewind(intern TSRMLS_CC); +} +/* }}} */ + /* {{{ iterator handler table */ zend_object_iterator_funcs spl_array_it_funcs = { spl_array_it_dtor, @@ -954,53 +999,13 @@ return; } - if (Z_TYPE_PP(array) == IS_ARRAY) { - SEPARATE_ZVAL_IF_NOT_REF(array); - } - if (ZEND_NUM_ARGS() > 2) { intern->ce_get_iterator = ce_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) - { - 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_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) { - php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); - 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; - } - if (object == *array) { - intern->ar_flags |= SPL_ARRAY_IS_SELF; - intern->ar_flags &= ~SPL_ARRAY_USE_OTHER; - } else { - intern->ar_flags &= ~SPL_ARRAY_IS_SELF; - } - intern->ar_flags |= ar_flags; - Z_ADDREF_P(intern->array); - if (Z_TYPE_PP(array) == IS_OBJECT) { - zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties); - if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties) - || !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 %v is not compatible with %v", Z_OBJCE_PP(array)->name, intern->std.ce->name); - return; - } - } - - spl_array_rewind(intern TSRMLS_CC); + spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC); php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC); } @@ -1074,31 +1079,9 @@ 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); + } /* }}} */ http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt +++ php-src/ext/spl/tests/arrayObject_exchangeArray_basic1.phpt --TEST-- SPL: ArrayObject::exchangeArray() and copy-on-write references --FILE-- <?php $ao = new ArrayObject(); $swapIn = array(); $cowRef = $swapIn; // create a copy-on-write ref to $swapIn $ao->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) { [u"b"]=> unicode(25) "adding element to $swapIn" } --> cowRef: array(0) { } --> ao: object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> array(2) { [u"a"]=> unicode(21) "adding element to $ao" [u"c"]=> unicode(29) "adding another element to $ao" } } http://cvs.php.net/viewvc.cgi/php-src/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt?view=markup&rev=1.1 Index: php-src/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt +++ php-src/ext/spl/tests/arrayObject_exchangeArray_basic2.phpt --TEST-- SPL: ArrayObject::exchangeArray() with various object arguments --FILE-- <?php echo "--> exchangeArray(array):\n"; $ao = new ArrayObject(); $ao->exchangeArray(array('key'=>'original')); var_dump($ao['key']); var_dump($ao); echo "\n--> exchangeArray(normal object):\n"; $obj = new stdClass; $obj->key = 'normal object prop'; $ao->exchangeArray($obj); var_dump($ao['key']); var_dump($ao); echo "\n--> exchangeArray(ArrayObject):\n"; $obj = new ArrayObject(array('key'=>'ArrayObject element')); $ao->exchangeArray($obj); var_dump($ao['key']); var_dump($ao); echo "\n--> exchangeArray(ArrayIterator):\n"; $obj = new ArrayIterator(array('key'=>'ArrayIterator element')); $ao->exchangeArray($obj); var_dump($ao['key']); var_dump($ao); echo "\n--> exchangeArray(nested ArrayObject):\n"; $obj = new ArrayObject(new ArrayObject(array('key'=>'nested ArrayObject element'))); $ao->exchangeArray($obj); var_dump($ao['key']); var_dump($ao); ?> --EXPECTF-- --> exchangeArray(array): unicode(8) "original" object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> array(1) { [u"key"]=> unicode(8) "original" } } --> exchangeArray(normal object): unicode(18) "normal object prop" object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> object(stdClass)#%d (1) { [u"key"]=> unicode(18) "normal object prop" } } --> exchangeArray(ArrayObject): unicode(19) "ArrayObject element" object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> array(1) { [u"key"]=> unicode(19) "ArrayObject element" } } } --> exchangeArray(ArrayIterator): unicode(21) "ArrayIterator element" object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> object(ArrayIterator)#%d (1) { [u"storage":u"ArrayIterator":private]=> array(1) { [u"key"]=> unicode(21) "ArrayIterator element" } } } --> exchangeArray(nested ArrayObject): unicode(26) "nested ArrayObject element" object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> object(ArrayObject)#%d (1) { [u"storage":u"ArrayObject":private]=> array(1) { [u"key"]=> unicode(26) "nested ArrayObject element" } } } }
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php