robinf          Mon Aug  4 11:45:21 2008 UTC

  Added files:                 (Branch: PHP_5_3)
    /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.71.2.17.2.13.2.19&r2=1.71.2.17.2.13.2.20&diff_format=u
Index: php-src/ext/spl/spl_array.c
diff -u php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.19 
php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.20
--- php-src/ext/spl/spl_array.c:1.71.2.17.2.13.2.19     Sat Jul 26 12:34:10 2008
+++ php-src/ext/spl/spl_array.c Mon Aug  4 11:45:21 2008
@@ -16,7 +16,7 @@
    +----------------------------------------------------------------------+
  */
 
-/* $Id: spl_array.c,v 1.71.2.17.2.13.2.19 2008/07/26 12:34:10 lbarnaud Exp $ */
+/* $Id: spl_array.c,v 1.71.2.17.2.13.2.20 2008/08/04 11:45:21 robinf Exp $ */
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
@@ -892,6 +892,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 %s is not compatible with %s", 
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,
@@ -949,10 +994,6 @@
                return;
        }
 
-       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);
@@ -964,43 +1005,7 @@
 
        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 %s is not compatible with %s", 
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);
 }
@@ -1081,31 +1086,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

Reply via email to