29
29
#include "php_spl.h"
30
30
#include "spl_array_arginfo.h"
31
31
#include "spl_functions.h"
32
- #include "spl_engine.h"
33
32
#include "spl_iterators.h"
34
33
#include "spl_array.h"
35
34
#include "spl_exceptions.h"
@@ -63,6 +62,8 @@ typedef struct _spl_array_object {
63
62
uint32_t ht_iter ;
64
63
int ar_flags ;
65
64
unsigned char nApplyCount ;
65
+ bool is_child ;
66
+ Bucket * bucket ;
66
67
zend_function * fptr_offset_get ;
67
68
zend_function * fptr_offset_set ;
68
69
zend_function * fptr_offset_has ;
@@ -167,6 +168,8 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_o
167
168
object_properties_init (& intern -> std , class_type );
168
169
169
170
intern -> ar_flags = 0 ;
171
+ intern -> is_child = false;
172
+ intern -> bucket = NULL ;
170
173
intern -> ce_get_iterator = spl_ce_ArrayIterator ;
171
174
if (orig ) {
172
175
spl_array_object * other = spl_array_from_obj (orig );
@@ -477,11 +480,23 @@ static zval *spl_array_read_dimension(zend_object *object, zval *offset, int typ
477
480
return spl_array_read_dimension_ex (1 , object , offset , type , rv );
478
481
} /* }}} */
479
482
483
+ static uint32_t spl_array_set_refcount (spl_array_object * intern , HashTable * ht , uint32_t refcount ) /* {{{ */
484
+ {
485
+ uint32_t old_refcount = 0 ;
486
+ if (intern -> is_child ) {
487
+ old_refcount = GC_REFCOUNT (ht );
488
+ GC_SET_REFCOUNT (ht , refcount );
489
+ }
490
+
491
+ return old_refcount ;
492
+ } /* }}} */
493
+
480
494
static void spl_array_write_dimension_ex (int check_inherited , zend_object * object , zval * offset , zval * value ) /* {{{ */
481
495
{
482
496
spl_array_object * intern = spl_array_from_obj (object );
483
497
HashTable * ht ;
484
498
spl_hash_key key ;
499
+ uint32_t refcount = 0 ;
485
500
486
501
if (check_inherited && intern -> fptr_offset_set ) {
487
502
zval tmp ;
@@ -502,7 +517,12 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
502
517
Z_TRY_ADDREF_P (value );
503
518
if (!offset || Z_TYPE_P (offset ) == IS_NULL ) {
504
519
ht = spl_array_get_hash_table (intern );
520
+ refcount = spl_array_set_refcount (intern , ht , 1 );
505
521
zend_hash_next_index_insert (ht , value );
522
+
523
+ if (refcount ) {
524
+ spl_array_set_refcount (intern , ht , refcount );
525
+ }
506
526
return ;
507
527
}
508
528
@@ -513,12 +533,17 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
513
533
}
514
534
515
535
ht = spl_array_get_hash_table (intern );
536
+ refcount = spl_array_set_refcount (intern , ht , 1 );
516
537
if (key .key ) {
517
538
zend_hash_update_ind (ht , key .key , value );
518
539
spl_hash_key_release (& key );
519
540
} else {
520
541
zend_hash_index_update (ht , key .h , value );
521
542
}
543
+
544
+ if (refcount ) {
545
+ spl_array_set_refcount (intern , ht , refcount );
546
+ }
522
547
} /* }}} */
523
548
524
549
static void spl_array_write_dimension (zend_object * object , zval * offset , zval * value ) /* {{{ */
@@ -531,6 +556,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
531
556
HashTable * ht ;
532
557
spl_array_object * intern = spl_array_from_obj (object );
533
558
spl_hash_key key ;
559
+ uint32_t refcount = 0 ;
534
560
535
561
if (check_inherited && intern -> fptr_offset_del ) {
536
562
zend_call_method_with_1_params (object , object -> ce , & intern -> fptr_offset_del , "offsetUnset" , NULL , offset );
@@ -548,6 +574,7 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
548
574
}
549
575
550
576
ht = spl_array_get_hash_table (intern );
577
+ refcount = spl_array_set_refcount (intern , ht , 1 );
551
578
if (key .key ) {
552
579
zval * data = zend_hash_find (ht , key .key );
553
580
if (data ) {
@@ -570,6 +597,10 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
570
597
} else {
571
598
zend_hash_index_del (ht , key .h );
572
599
}
600
+
601
+ if (refcount ) {
602
+ spl_array_set_refcount (intern , ht , refcount );
603
+ }
573
604
} /* }}} */
574
605
575
606
static void spl_array_unset_dimension (zend_object * object , zval * offset ) /* {{{ */
@@ -1056,8 +1087,12 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
1056
1087
if (Z_REFCOUNT_P (array ) == 1 ) {
1057
1088
ZVAL_COPY (& intern -> array , array );
1058
1089
} else {
1059
- //??? TODO: try to avoid array duplication
1060
1090
ZVAL_ARR (& intern -> array , zend_array_dup (Z_ARR_P (array )));
1091
+ if (intern -> is_child ) {
1092
+ Z_TRY_DELREF_P (& intern -> bucket -> val );
1093
+ intern -> bucket -> val = intern -> array ;
1094
+ Z_TRY_ADDREF_P (& intern -> array );
1095
+ }
1061
1096
}
1062
1097
} else {
1063
1098
if (Z_OBJ_HT_P (array ) == & spl_handler_ArrayObject || Z_OBJ_HT_P (array ) == & spl_handler_ArrayIterator ) {
@@ -1544,6 +1579,16 @@ PHP_METHOD(RecursiveArrayIterator, hasChildren)
1544
1579
}
1545
1580
/* }}} */
1546
1581
1582
+ static void spl_instantiate_child_arg (zend_class_entry * pce , zval * retval , zval * arg1 , zval * arg2 ) /* {{{ */
1583
+ {
1584
+ object_init_ex (retval , pce );
1585
+ spl_array_object * new_intern = Z_SPLARRAY_P (retval );
1586
+ new_intern -> is_child = true;
1587
+ new_intern -> bucket = (Bucket * )((char * )(arg1 ) - XtOffsetOf (Bucket , val ));
1588
+ zend_call_known_instance_method_with_2_params (pce -> constructor , Z_OBJ_P (retval ), NULL , arg1 , arg2 );
1589
+ }
1590
+ /* }}} */
1591
+
1547
1592
/* {{{ Create a sub iterator for the current element (same class as $this) */
1548
1593
PHP_METHOD (RecursiveArrayIterator , getChildren )
1549
1594
{
@@ -1574,7 +1619,7 @@ PHP_METHOD(RecursiveArrayIterator, getChildren)
1574
1619
}
1575
1620
1576
1621
ZVAL_LONG (& flags , intern -> ar_flags );
1577
- spl_instantiate_arg_ex2 (Z_OBJCE_P (ZEND_THIS ), return_value , entry , & flags );
1622
+ spl_instantiate_child_arg (Z_OBJCE_P (ZEND_THIS ), return_value , entry , & flags );
1578
1623
}
1579
1624
/* }}} */
1580
1625
0 commit comments