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