PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - spl - spl_array.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 703
Code covered: 86.5 % Executed lines: 608
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Marcus Boerger <helly@php.net>                              |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : 
      19                 : /* $Id: spl_array.c 280904 2009-05-21 13:26:29Z lbarnaud $ */
      20                 : 
      21                 : #ifdef HAVE_CONFIG_H
      22                 : # include "config.h"
      23                 : #endif
      24                 : 
      25                 : #include "php.h"
      26                 : #include "php_ini.h"
      27                 : #include "ext/standard/info.h"
      28                 : #include "zend_interfaces.h"
      29                 : #include "zend_exceptions.h"
      30                 : 
      31                 : #include "php_spl.h"
      32                 : #include "spl_functions.h"
      33                 : #include "spl_engine.h"
      34                 : #include "spl_iterators.h"
      35                 : #include "spl_array.h"
      36                 : #include "spl_exceptions.h"
      37                 : 
      38                 : zend_object_handlers spl_handler_ArrayObject;
      39                 : PHPAPI zend_class_entry  *spl_ce_ArrayObject;
      40                 : 
      41                 : zend_object_handlers spl_handler_ArrayIterator;
      42                 : PHPAPI zend_class_entry  *spl_ce_ArrayIterator;
      43                 : PHPAPI zend_class_entry  *spl_ce_RecursiveArrayIterator;
      44                 : 
      45                 : #define SPL_ARRAY_STD_PROP_LIST      0x00000001
      46                 : #define SPL_ARRAY_ARRAY_AS_PROPS     0x00000002
      47                 : #define SPL_ARRAY_OVERLOADED_REWIND  0x00010000
      48                 : #define SPL_ARRAY_OVERLOADED_VALID   0x00020000
      49                 : #define SPL_ARRAY_OVERLOADED_KEY     0x00040000
      50                 : #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
      51                 : #define SPL_ARRAY_OVERLOADED_NEXT    0x00100000
      52                 : #define SPL_ARRAY_IS_REF             0x01000000
      53                 : #define SPL_ARRAY_IS_SELF            0x02000000
      54                 : #define SPL_ARRAY_USE_OTHER          0x04000000
      55                 : #define SPL_ARRAY_INT_MASK           0xFFFF0000
      56                 : #define SPL_ARRAY_CLONE_MASK         0x03000007
      57                 : 
      58                 : typedef struct _spl_array_object {
      59                 :         zend_object       std;
      60                 :         zval              *array;
      61                 :         zval              *retval;
      62                 :         HashPosition      pos;
      63                 :         int               ar_flags;
      64                 :         int               is_self;
      65                 :         zend_function *   fptr_offset_get;
      66                 :         zend_function *   fptr_offset_set;
      67                 :         zend_function *   fptr_offset_has;
      68                 :         zend_function *   fptr_offset_del;
      69                 :         zend_class_entry* ce_get_iterator;
      70                 : } spl_array_object;
      71                 : 
      72           12984 : static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) {
      73           12984 :         if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
      74             136 :                 return intern->std.properties;
      75           12848 :         } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
      76            2314 :                 spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
      77            2314 :                 return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
      78           10534 :         } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
      79              16 :                 return intern->std.properties;
      80                 :         } else {
      81           10518 :                 return HASH_OF(intern->array);
      82                 :         }
      83                 : }
      84                 : 
      85                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
      86                 : 
      87                 : SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
      88             722 : {
      89             722 :         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
      90                 :         Bucket *p;
      91                 : 
      92                 : /*      IS_CONSISTENT(ht);*/
      93                 : 
      94                 : /*      HASH_PROTECT_RECURSION(ht);*/
      95             722 :         p = ht->pListHead;
      96            2185 :         while (p != NULL) {
      97            1430 :                 if (p == intern->pos) {
      98             689 :                         return SUCCESS;
      99                 :                 }
     100             741 :                 p = p->pListNext;
     101                 :         }
     102                 : /*      HASH_UNPROTECT_RECURSION(ht); */
     103              33 :         spl_array_rewind(intern TSRMLS_CC);
     104              33 :         return FAILURE;
     105                 : }
     106                 : /* }}} */
     107                 : 
     108                 : /* {{{ spl_array_object_free_storage */
     109                 : static void spl_array_object_free_storage(void *object TSRMLS_DC)
     110             491 : {
     111             491 :         spl_array_object *intern = (spl_array_object *)object;
     112                 : 
     113             491 :         zend_object_std_dtor(&intern->std TSRMLS_CC);
     114                 : 
     115             491 :         zval_ptr_dtor(&intern->array);
     116             491 :         zval_ptr_dtor(&intern->retval);
     117                 : 
     118             491 :         efree(object);
     119             491 : }
     120                 : /* }}} */
     121                 : 
     122                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
     123                 : 
     124                 : /* {{{ spl_array_object_new */
     125                 : static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
     126             491 : {
     127                 :         zend_object_value retval;
     128                 :         spl_array_object *intern;
     129                 :         zval *tmp;
     130             491 :         zend_class_entry * parent = class_type;
     131             491 :         int inherited = 0;
     132                 : 
     133             491 :         intern = emalloc(sizeof(spl_array_object));
     134             491 :         memset(intern, 0, sizeof(spl_array_object));
     135             491 :         *obj = intern;
     136             491 :         ALLOC_INIT_ZVAL(intern->retval);
     137                 : 
     138             491 :         zend_object_std_init(&intern->std, class_type TSRMLS_CC);
     139             491 :         zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
     140                 : 
     141             491 :         intern->ar_flags = 0;
     142             491 :         intern->ce_get_iterator = spl_ce_ArrayIterator;
     143             491 :         if (orig) {
     144              73 :                 spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
     145                 : 
     146              73 :                 intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
     147              73 :                 intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
     148              73 :                 intern->ce_get_iterator = other->ce_get_iterator;
     149              73 :                 if (clone_orig) {
     150               8 :                         intern->array = other->array;
     151               8 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
     152               6 :                                 MAKE_STD_ZVAL(intern->array);
     153               6 :                                 array_init(intern->array);
     154               6 :                                 zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
     155                 :                         }
     156               8 :                         if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
     157               2 :                                 ZVAL_ADDREF(other->array);
     158                 :                         }
     159                 :                 } else {
     160              65 :                         intern->array = orig;
     161              65 :                         ZVAL_ADDREF(intern->array);
     162              65 :                         intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
     163                 :                 }
     164                 :         } else {
     165             418 :                 MAKE_STD_ZVAL(intern->array);
     166             418 :                 array_init(intern->array);
     167             418 :                 intern->ar_flags &= ~SPL_ARRAY_IS_REF;
     168                 :         }
     169                 : 
     170             491 :         retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
     171            1098 :         while (parent) {
     172             607 :                 if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
     173             368 :                         retval.handlers = &spl_handler_ArrayIterator;
     174             368 :                         class_type->get_iterator = spl_array_get_iterator;
     175             368 :                         break;
     176             239 :                 } else if (parent == spl_ce_ArrayObject) {
     177             123 :                         retval.handlers = &spl_handler_ArrayObject;
     178             123 :                         break;
     179                 :                 }
     180             116 :                 parent = parent->parent;
     181             116 :                 inherited = 1;
     182                 :         }
     183             491 :         if (!parent) { /* this must never happen */
     184               0 :                 php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
     185                 :         }
     186             491 :         if (inherited) {
     187             116 :                 zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
     188             116 :                 if (intern->fptr_offset_get->common.scope == parent) {
     189              85 :                         intern->fptr_offset_get = NULL;
     190                 :                 }
     191             116 :                 zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
     192             116 :                 if (intern->fptr_offset_set->common.scope == parent) {
     193              85 :                         intern->fptr_offset_set = NULL;
     194                 :                 }
     195             116 :                 zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
     196             116 :                 if (intern->fptr_offset_has->common.scope == parent) {
     197              88 :                         intern->fptr_offset_has = NULL;
     198                 :                 }
     199             116 :                 zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
     200             116 :                 if (intern->fptr_offset_del->common.scope == parent) {
     201              88 :                         intern->fptr_offset_del = NULL;
     202                 :                 }
     203                 :         }
     204                 :         /* Cache iterator functions if ArrayIterator or derived. Check current's */
     205                 :         /* cache since only current is always required */
     206             491 :         if (retval.handlers == &spl_handler_ArrayIterator) {
     207             368 :                 if (!class_type->iterator_funcs.zf_current) {
     208             132 :                         zend_hash_find(&class_type->function_table, "rewind",  sizeof("rewind"),  (void **) &class_type->iterator_funcs.zf_rewind);
     209             132 :                         zend_hash_find(&class_type->function_table, "valid",   sizeof("valid"),   (void **) &class_type->iterator_funcs.zf_valid);
     210             132 :                         zend_hash_find(&class_type->function_table, "key",     sizeof("key"),     (void **) &class_type->iterator_funcs.zf_key);
     211             132 :                         zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
     212             132 :                         zend_hash_find(&class_type->function_table, "next",    sizeof("next"),    (void **) &class_type->iterator_funcs.zf_next);
     213                 :                 }
     214             368 :                 if (inherited) {
     215              89 :                         if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
     216              89 :                         if (class_type->iterator_funcs.zf_valid->common.scope   != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
     217              89 :                         if (class_type->iterator_funcs.zf_key->common.scope     != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
     218              89 :                         if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
     219              89 :                         if (class_type->iterator_funcs.zf_next->common.scope    != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
     220                 :                 }
     221                 :         }
     222                 : 
     223             491 :         spl_array_rewind(intern TSRMLS_CC);
     224             491 :         return retval;
     225                 : }
     226                 : /* }}} */
     227                 : 
     228                 : /* {{{ spl_array_object_new */
     229                 : static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
     230             418 : {
     231                 :         spl_array_object *tmp;
     232             418 :         return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
     233                 : }
     234                 : /* }}} */
     235                 : 
     236                 : /* {{{ spl_array_object_clone */
     237                 : static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
     238               8 : {
     239                 :         zend_object_value new_obj_val;
     240                 :         zend_object *old_object;
     241                 :         zend_object *new_object;
     242               8 :         zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
     243                 :         spl_array_object *intern;
     244                 : 
     245               8 :         old_object = zend_objects_get_address(zobject TSRMLS_CC);
     246               8 :         new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
     247               8 :         new_object = &intern->std;
     248                 : 
     249               8 :         zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
     250                 : 
     251               8 :         return new_obj_val;
     252                 : }
     253                 : /* }}} */
     254                 : 
     255                 : static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     256              95 : {
     257              95 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     258                 :         zval **retval;
     259                 :         long index;
     260              95 :         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     261                 : 
     262                 : /*  We cannot get the pointer pointer so we don't allow it here for now
     263                 :         if (check_inherited && intern->fptr_offset_get) {
     264                 :                 return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
     265                 :         }*/
     266                 : 
     267              95 :         if (!offset) {
     268               1 :                 return &EG(uninitialized_zval_ptr);
     269                 :         }
     270                 :         
     271              94 :         switch(Z_TYPE_P(offset)) {
     272                 :         case IS_STRING:
     273              65 :                 if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
     274              23 :                         if (type == BP_VAR_W || type == BP_VAR_RW) {
     275                 :                                 zval *value;
     276               1 :                                 ALLOC_INIT_ZVAL(value);
     277               1 :                                 zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
     278               1 :                                 zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval);
     279               1 :                                 return retval;
     280                 :                         } else {
     281              22 :                                 zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(offset));
     282              22 :                                 return &EG(uninitialized_zval_ptr);
     283                 :                         }
     284                 :                 } else {
     285              42 :                         return retval;
     286                 :                 }
     287                 :         case IS_DOUBLE:
     288                 :         case IS_RESOURCE:
     289                 :         case IS_BOOL: 
     290                 :         case IS_LONG: 
     291              29 :                 if (offset->type == IS_DOUBLE) {
     292               0 :                         index = (long)Z_DVAL_P(offset);
     293                 :                 } else {
     294              29 :                         index = Z_LVAL_P(offset);
     295                 :                 }
     296              29 :                 if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
     297               2 :                         if (type == BP_VAR_W || type == BP_VAR_RW) {
     298                 :                                 zval *value;
     299               0 :                                 ALLOC_INIT_ZVAL(value);
     300               0 :                                 zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
     301               0 :                                 zend_hash_index_find(ht, index, (void **) &retval);
     302               0 :                                 return retval;
     303                 :                         } else {
     304               2 :                                 zend_error(E_NOTICE, "Undefined offset:  %ld", Z_LVAL_P(offset));
     305               2 :                                 return &EG(uninitialized_zval_ptr);
     306                 :                         }
     307                 :                 } else {
     308              27 :                         return retval;
     309                 :                 }
     310                 :                 break;
     311                 :         default:
     312               0 :                 zend_error(E_WARNING, "Illegal offset type");
     313               0 :                 return &EG(uninitialized_zval_ptr);
     314                 :         }
     315                 : } /* }}} */
     316                 : 
     317                 : static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     318             101 : {
     319                 :         zval **ret;
     320                 : 
     321             101 :         if (check_inherited) {
     322              95 :                 spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     323              95 :                 if (intern->fptr_offset_get) {
     324                 :                         zval *rv;
     325               6 :                         SEPARATE_ARG_IF_REF(offset);
     326               6 :                         zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);        
     327               6 :                         zval_ptr_dtor(&offset);
     328               6 :                         if (rv) {
     329               5 :                                 zval_ptr_dtor(&intern->retval);
     330               5 :                                 MAKE_STD_ZVAL(intern->retval);
     331               5 :                                 ZVAL_ZVAL(intern->retval, rv, 1, 1);
     332               5 :                                 return intern->retval;
     333                 :                         }
     334               1 :                         return EG(uninitialized_zval_ptr);
     335                 :                 }
     336                 :         }
     337              95 :         ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
     338                 : 
     339                 :         /* When in a write context,
     340                 :          * ZE has to be fooled into thinking this is in a reference set
     341                 :          * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
     342              95 :         if ((type == BP_VAR_W || type == BP_VAR_RW) && !(*ret)->is_ref) {
     343               3 :                 if ((*ret)->refcount > 1) {
     344                 :                         zval *newval;
     345                 : 
     346                 :                         /* Separate */
     347               1 :                         MAKE_STD_ZVAL(newval);
     348               1 :                         *newval = **ret;
     349               1 :                         zval_copy_ctor(newval);
     350               1 :                         newval->refcount = 1;
     351                 : 
     352                 :                         /* Replace */
     353               1 :                         (*ret)->refcount--;
     354               1 :                         *ret = newval;
     355                 :                 }
     356                 : 
     357               3 :                 (*ret)->is_ref = 1;
     358                 :         }
     359                 : 
     360              95 :         return *ret;
     361                 : } /* }}} */
     362                 : 
     363                 : static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
     364              95 : {
     365              95 :         return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
     366                 : } /* }}} */
     367                 : 
     368                 : static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     369             120 : {
     370             120 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     371                 :         long index;
     372                 : 
     373             120 :         if (check_inherited && intern->fptr_offset_set) {
     374               6 :                 if (!offset) {
     375               4 :                         ALLOC_INIT_ZVAL(offset);
     376                 :                 } else {
     377               2 :                         SEPARATE_ARG_IF_REF(offset);
     378                 :                 }
     379               6 :                 zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
     380               6 :                 zval_ptr_dtor(&offset);
     381               6 :                 return;
     382                 :         }
     383                 :         
     384             114 :         if (!offset) {
     385              37 :                 value->refcount++;
     386              37 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     387              37 :                 return;
     388                 :         }
     389              77 :         switch(Z_TYPE_P(offset)) {
     390                 :         case IS_STRING:
     391              53 :                 if (*Z_STRVAL_P(offset) == '\0') {
     392               2 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "An offset must not begin with \\0 or be empty", 0 TSRMLS_CC);
     393               2 :                         return;
     394                 :                 }
     395              51 :                 value->refcount++;
     396              51 :                 zend_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
     397              51 :                 return;
     398                 :         case IS_DOUBLE:
     399                 :         case IS_RESOURCE:
     400                 :         case IS_BOOL: 
     401                 :         case IS_LONG: 
     402              20 :                 if (offset->type == IS_DOUBLE) {
     403               0 :                         index = (long)Z_DVAL_P(offset);
     404                 :                 } else {
     405              20 :                         index = Z_LVAL_P(offset);
     406                 :                 }
     407              20 :                 value->refcount++;
     408              20 :                 zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
     409              20 :                 return;
     410                 :         case IS_NULL:
     411               4 :                 value->refcount++;
     412               4 :                 zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
     413               4 :                 return;
     414                 :         default:
     415               0 :                 zend_error(E_WARNING, "Illegal offset type");
     416               0 :                 return;
     417                 :         }
     418                 : } /* }}} */
     419                 : 
     420                 : static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
     421             103 : {
     422             103 :         spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
     423             103 : } /* }}} */
     424                 : 
     425                 : static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
     426              47 : {
     427              47 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     428                 :         long index;
     429                 : 
     430              47 :         if (check_inherited && intern->fptr_offset_del) {
     431               0 :                 SEPARATE_ARG_IF_REF(offset);
     432               0 :                 zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
     433               0 :                 zval_ptr_dtor(&offset);
     434               0 :                 return;
     435                 :         }
     436                 : 
     437              47 :         switch(Z_TYPE_P(offset)) {
     438                 :         case IS_STRING:
     439              33 :                 if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
     440               1 :                         if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
     441               0 :                                 zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
     442                 :                         }
     443                 :                 } else {
     444              32 :                         if (zend_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
     445               9 :                                 zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
     446                 :                         }
     447                 :                 }
     448              33 :                 break;
     449                 :         case IS_DOUBLE:
     450                 :         case IS_RESOURCE:
     451                 :         case IS_BOOL: 
     452                 :         case IS_LONG: 
     453              14 :                 if (offset->type == IS_DOUBLE) {
     454               0 :                         index = (long)Z_DVAL_P(offset);
     455                 :                 } else {
     456              14 :                         index = Z_LVAL_P(offset);
     457                 :                 }
     458              14 :                 if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
     459               2 :                         zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
     460                 :                 }
     461              14 :                 break;
     462                 :         default:
     463               0 :                 zend_error(E_WARNING, "Illegal offset type");
     464               0 :                 return;
     465                 :         }
     466              47 :         spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
     467                 : } /* }}} */
     468                 : 
     469                 : static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
     470              39 : {
     471              39 :         spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
     472              39 : } /* }}} */
     473                 : 
     474                 : static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     475              56 : {
     476              56 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     477                 :         long index;
     478                 :         zval *rv, **tmp;
     479                 : 
     480              56 :         if (check_inherited && intern->fptr_offset_has) {
     481               0 :                 SEPARATE_ARG_IF_REF(offset);
     482               0 :                 zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
     483               0 :                 zval_ptr_dtor(&offset);
     484               0 :                 if (rv && zend_is_true(rv)) {
     485               0 :                         zval_ptr_dtor(&rv);
     486               0 :                         return 1;
     487                 :                 }
     488               0 :                 if (rv) {
     489               0 :                         zval_ptr_dtor(&rv);
     490                 :                 }
     491               0 :                 return 0;
     492                 :         }
     493                 :         
     494              56 :         switch(Z_TYPE_P(offset)) {
     495                 :         case IS_STRING:
     496              47 :                 if (check_empty) {
     497               5 :                         if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE && zend_is_true(*tmp)) {
     498               1 :                                 return 1;
     499                 :                         }
     500               4 :                         return 0;
     501                 :                 } else {
     502              42 :                         return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
     503                 :                 }
     504                 :         case IS_DOUBLE:
     505                 :         case IS_RESOURCE:
     506                 :         case IS_BOOL: 
     507                 :         case IS_LONG: 
     508               9 :                 if (offset->type == IS_DOUBLE) {
     509               0 :                         index = (long)Z_DVAL_P(offset);
     510                 :                 } else {
     511               9 :                         index = Z_LVAL_P(offset);
     512                 :                 }
     513               9 :                 if (check_empty) {
     514               4 :                         HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     515               4 :                         if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE && zend_is_true(*tmp)) {
     516               3 :                                 return 1;
     517                 :                         }
     518               1 :                         return 0;
     519                 :                 } else {
     520               5 :                         return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
     521                 :                 }
     522                 :         default:
     523               0 :                 zend_error(E_WARNING, "Illegal offset type");
     524                 :         }
     525               0 :         return 0;
     526                 : } /* }}} */
     527                 : 
     528                 : static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
     529              51 : {
     530              51 :         return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
     531                 : } /* }}} */
     532                 : 
     533                 : /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
     534                 :        proto bool ArrayIterator::offsetExists(mixed $index)
     535                 :  Returns whether the requested $index exists. */
     536                 : SPL_METHOD(Array, offsetExists)
     537               5 : {
     538                 :         zval *index;
     539               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     540               0 :                 return;
     541                 :         }
     542               5 :         RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
     543                 : } /* }}} */
     544                 : 
     545                 : /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
     546                 :        proto mixed ArrayIterator::offsetGet(mixed $index)
     547                 :  Returns the value at the specified $index. */
     548                 : SPL_METHOD(Array, offsetGet)
     549               6 : {
     550                 :         zval *index, *value;
     551               6 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     552               0 :                 return;
     553                 :         }
     554               6 :         value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
     555               6 :         RETURN_ZVAL(value, 1, 0);
     556                 : } /* }}} */
     557                 : 
     558                 : /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
     559                 :        proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
     560                 :  Sets the value at the specified $index to $newval. */
     561                 : SPL_METHOD(Array, offsetSet)
     562              17 : {
     563                 :         zval *index, *value;
     564              17 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
     565               0 :                 return;
     566                 :         }
     567              17 :         spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
     568                 : } /* }}} */
     569                 : 
     570                 : 
     571                 : void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
     572              21 : {
     573              21 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     574              21 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     575                 : 
     576              21 :         if (!aht) {
     577               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
     578               0 :                 return;
     579                 :         }
     580                 :         
     581              21 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     582               1 :                 php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
     583               0 :                 return;
     584                 :         }
     585                 : 
     586              20 :         spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
     587              20 :         if (!intern->pos) {
     588              10 :                 intern->pos = aht->pListTail;
     589                 :         }
     590                 : } /* }}} */
     591                 : 
     592                 : /* {{{ proto void ArrayObject::append(mixed $newval)
     593                 :        proto void ArrayIterator::append(mixed $newval)
     594                 :  Appends the value (cannot be called for objects). */
     595                 : SPL_METHOD(Array, append)
     596               9 : {
     597                 :         zval *value;
     598                 : 
     599               9 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
     600               0 :                 return;
     601                 :         }
     602               9 :         spl_array_iterator_append(getThis(), value TSRMLS_CC);
     603                 : } /* }}} */
     604                 : 
     605                 : /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
     606                 :        proto void ArrayIterator::offsetUnset(mixed $index)
     607                 :  Unsets the value at the specified $index. */
     608                 : SPL_METHOD(Array, offsetUnset)
     609               8 : {
     610                 :         zval *index;
     611               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
     612               0 :                 return;
     613                 :         }
     614               8 :         spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
     615                 : } /* }}} */
     616                 : 
     617                 : /* {{ proto array ArrayObject::getArrayCopy()
     618                 :       proto array ArrayIterator::getArrayCopy()
     619                 :  Return a copy of the contained array */
     620                 : SPL_METHOD(Array, getArrayCopy)
     621              11 : {
     622              11 :         zval *object = getThis(), *tmp;
     623              11 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     624                 :     
     625              11 :     array_init(return_value);
     626              11 :         zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
     627              11 : } /* }}} */
     628                 : 
     629                 : static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
     630             139 : {
     631             139 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     632                 : 
     633             139 :         return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
     634                 : } /* }}} */
     635                 : 
     636                 : static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
     637              73 : {
     638              73 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     639                 : 
     640              73 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     641                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     642              25 :                 return spl_array_read_dimension(object, member, type TSRMLS_CC);
     643                 :         }
     644              48 :         return std_object_handlers.read_property(object, member, type TSRMLS_CC);
     645                 : } /* }}} */
     646                 : 
     647                 : static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
     648              75 : {
     649              75 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     650                 : 
     651              75 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     652                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     653              15 :                 spl_array_write_dimension(object, member, value TSRMLS_CC);
     654              15 :                 return;
     655                 :         }
     656              60 :         std_object_handlers.write_property(object, member, value TSRMLS_CC);
     657                 : } /* }}} */
     658                 : 
     659                 : static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
     660               0 : {
     661               0 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     662                 : 
     663               0 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     664                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     665               0 :                 return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC);         
     666                 :         }
     667               0 :         return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
     668                 : } /* }}} */
     669                 : 
     670                 : static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
     671              44 : {
     672              44 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     673                 : 
     674              44 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     675                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     676              22 :                 return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
     677                 :         }
     678              22 :         return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
     679                 : 
     680                 : } /* }}} */
     681                 : 
     682                 : static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
     683              25 : {
     684              25 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     685                 : 
     686              25 :         if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
     687                 :         && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
     688              11 :                 spl_array_unset_dimension(object, member TSRMLS_CC);
     689              11 :                 spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
     690              11 :                 return;
     691                 :         }
     692              14 :         std_object_handlers.unset_property(object, member TSRMLS_CC);
     693                 : } /* }}} */
     694                 : 
     695                 : static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ */
     696            1530 : {
     697                 :         char *string_key;
     698                 :         uint string_length;
     699                 :         ulong num_key;
     700            1530 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     701                 : 
     702            1530 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     703                 :                 do {
     704             477 :                         if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
     705             177 :                                 if (!string_length || string_key[0]) {
     706             141 :                                         return SUCCESS;
     707                 :                                 }
     708                 :                         } else {
     709             300 :                                 return SUCCESS;
     710                 :                         }
     711              36 :                         if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
     712               0 :                                 return FAILURE;
     713                 :                         }
     714              36 :                         zend_hash_move_forward_ex(aht, &intern->pos);
     715              36 :                 } while (1);
     716                 :         }
     717            1089 :         return FAILURE;
     718                 : }
     719                 : /* }}} */
     720                 : 
     721                 : static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
     722            1024 : {
     723            1024 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     724                 : 
     725            1024 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
     726               2 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
     727               2 :                 return FAILURE;
     728                 :         } else {
     729            1022 :                 zend_hash_move_forward_ex(aht, &intern->pos);
     730            1022 :                 if (Z_TYPE_P(intern->array) == IS_OBJECT) {
     731             206 :                         return spl_array_skip_protected(intern TSRMLS_CC);
     732                 :                 } else {
     733             816 :                         return zend_hash_has_more_elements_ex(aht, &intern->pos);
     734                 :                 }
     735                 :         }
     736                 : } /* }}} */
     737                 : 
     738                 : /* define an overloaded iterator structure */
     739                 : typedef struct {
     740                 :         zend_user_iterator    intern;
     741                 :         spl_array_object      *object;
     742                 : } spl_array_it;
     743                 : 
     744                 : static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     745             348 : {
     746             348 :         spl_array_it *iterator = (spl_array_it *)iter;
     747                 : 
     748             348 :         zend_user_it_invalidate_current(iter TSRMLS_CC);
     749             348 :         zval_ptr_dtor((zval**)&iterator->intern.it.data);
     750                 : 
     751             348 :         efree(iterator);
     752             348 : }
     753                 : /* }}} */
     754                 :         
     755                 : static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     756            1582 : {
     757            1582 :         spl_array_it       *iterator = (spl_array_it *)iter;
     758            1582 :         spl_array_object   *object   = iterator->object;
     759            1582 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     760                 : 
     761            1582 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
     762             192 :                 return zend_user_it_valid(iter TSRMLS_CC);
     763                 :         } else {
     764            1390 :                 if (!aht) {
     765               2 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
     766               2 :                         return FAILURE;
     767                 :                 }
     768                 :         
     769            1388 :                 if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     770               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
     771               0 :                         return FAILURE;
     772                 :                 } else {
     773            1388 :                         return zend_hash_has_more_elements_ex(aht, &object->pos);
     774                 :                 }
     775                 :         }
     776                 : }
     777                 : /* }}} */
     778                 : 
     779                 : static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
     780             786 : {
     781             786 :         spl_array_it       *iterator = (spl_array_it *)iter;
     782             786 :         spl_array_object   *object   = iterator->object;
     783             786 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     784                 : 
     785             786 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
     786              93 :                 zend_user_it_get_current_data(iter, data TSRMLS_CC);
     787                 :         } else {
     788             693 :                 if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
     789               0 :                         *data = NULL;
     790                 :                 }
     791                 :         }
     792             786 : }
     793                 : /* }}} */
     794                 : 
     795                 : static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
     796             606 : {
     797             606 :         spl_array_it       *iterator = (spl_array_it *)iter;
     798             606 :         spl_array_object   *object   = iterator->object;
     799             606 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     800                 : 
     801             606 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
     802              72 :                 return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
     803                 :         } else {
     804             534 :                 if (!aht) {
     805               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     806               0 :                         return HASH_KEY_NON_EXISTANT;
     807                 :                 }
     808                 :         
     809             534 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     810               0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
     811               0 :                         return HASH_KEY_NON_EXISTANT;
     812                 :                 }
     813                 :         
     814             534 :                 return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
     815                 :         }
     816                 : }
     817                 : /* }}} */
     818                 : 
     819                 : static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     820             861 : {
     821             861 :         spl_array_it       *iterator = (spl_array_it *)iter;
     822             861 :         spl_array_object   *object   = iterator->object;
     823             861 :         HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
     824                 : 
     825             861 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
     826             101 :                 zend_user_it_move_forward(iter TSRMLS_CC);
     827                 :         } else {
     828             760 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     829             760 :                 if (!aht) {
     830               2 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
     831               2 :                         return;
     832                 :                 }
     833                 :         
     834             762 :                 if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
     835               4 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
     836                 :                 } else {
     837             754 :                         spl_array_next(object TSRMLS_CC);
     838                 :                 }
     839                 :         }
     840                 : }
     841                 : /* }}} */
     842                 : 
     843                 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
     844            1324 : {
     845            1324 :         HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
     846                 : 
     847            1324 :         if (!aht) {
     848               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
     849               0 :                 return;
     850                 :         }
     851                 : 
     852            1324 :         zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
     853            1324 :         spl_array_skip_protected(intern TSRMLS_CC);
     854                 : }
     855                 : /* }}} */
     856                 : 
     857                 : static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
     858             346 : {
     859             346 :         spl_array_it       *iterator = (spl_array_it *)iter;
     860             346 :         spl_array_object   *object   = iterator->object;
     861                 : 
     862             346 :         if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
     863              65 :                 zend_user_it_rewind(iter TSRMLS_CC);
     864                 :         } else {
     865             281 :                 zend_user_it_invalidate_current(iter TSRMLS_CC);
     866             281 :                 spl_array_rewind(object TSRMLS_CC);
     867                 :         }
     868             346 : }
     869                 : /* }}} */
     870                 : 
     871                 : /* iterator handler table */
     872                 : zend_object_iterator_funcs spl_array_it_funcs = {
     873                 :         spl_array_it_dtor,
     874                 :         spl_array_it_valid,
     875                 :         spl_array_it_get_current_data,
     876                 :         spl_array_it_get_current_key,
     877                 :         spl_array_it_move_forward,
     878                 :         spl_array_it_rewind
     879                 : };
     880                 : 
     881                 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
     882             349 : {
     883                 :         spl_array_it       *iterator;
     884             349 :         spl_array_object   *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     885                 : 
     886             349 :         if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
     887               1 :                 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
     888                 :         }
     889                 : 
     890             348 :         iterator     = emalloc(sizeof(spl_array_it));
     891                 : 
     892             348 :         object->refcount++;
     893             348 :         iterator->intern.it.data = (void*)object;
     894             348 :         iterator->intern.it.funcs = &spl_array_it_funcs;
     895             348 :         iterator->intern.ce = ce;
     896             348 :         iterator->intern.value = NULL;
     897             348 :         iterator->object = array_object;
     898                 :         
     899             348 :         return (zend_object_iterator*)iterator;
     900                 : }
     901                 : /* }}} */
     902                 : 
     903                 : /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
     904                 :        proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
     905                 :  Cronstructs a new array iterator from a path. */
     906                 : SPL_METHOD(Array, __construct)
     907             415 : {
     908             415 :         zval *object = getThis();
     909                 :         spl_array_object *intern;
     910                 :         zval **array;
     911             415 :         long ar_flags = 0;
     912             415 :         zend_class_entry * ce_get_iterator = spl_ce_Iterator;
     913                 : 
     914             415 :         if (ZEND_NUM_ARGS() == 0) {
     915              30 :                 return; /* nothing to do */
     916                 :         }
     917             385 :         php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
     918                 : 
     919             385 :         intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     920                 : 
     921             385 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
     922               5 :                 php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     923               5 :                 return;
     924                 :         }
     925                 : 
     926             380 :         if (Z_TYPE_PP(array) == IS_ARRAY) {
     927             325 :                 SEPARATE_ZVAL_IF_NOT_REF(array);
     928                 :         }
     929                 : 
     930             380 :         if (ZEND_NUM_ARGS() > 2) {
     931               3 :                 intern->ce_get_iterator = ce_get_iterator;
     932                 :         }
     933                 : 
     934             380 :         ar_flags &= ~SPL_ARRAY_INT_MASK;
     935                 : 
     936             403 :         if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
     937              23 :                 zval_ptr_dtor(&intern->array);
     938              23 :                 if (ZEND_NUM_ARGS() == 1)
     939                 :                 {
     940              10 :                         spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
     941              10 :                         ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
     942                 :                 }               
     943              23 :                 ar_flags |= SPL_ARRAY_USE_OTHER;
     944              23 :                 intern->array = *array;
     945                 :         } else {
     946             357 :                 if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
     947               1 :                         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     948               1 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
     949               1 :                         return;
     950                 :                 }
     951             356 :                 zval_ptr_dtor(&intern->array);
     952             356 :                 intern->array = *array;
     953                 :         }
     954             379 :         if (object == *array) {
     955               3 :                 intern->ar_flags |= SPL_ARRAY_IS_SELF;
     956               3 :                 intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
     957                 :         } else {
     958             376 :                 intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
     959                 :         }
     960             379 :         intern->ar_flags |= ar_flags;
     961             379 :         ZVAL_ADDREF(intern->array);
     962             379 :         if (Z_TYPE_PP(array) == IS_OBJECT) {
     963              54 :                 zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
     964              54 :                 if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
     965                 :                 || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
     966               0 :                         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     967               0 :                         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);
     968               0 :                         return;
     969                 :                 }
     970                 :         }
     971                 : 
     972             379 :         spl_array_rewind(intern TSRMLS_CC);
     973                 : 
     974             379 :         php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     975                 : }
     976                 : /* }}} */
     977                 : 
     978                 : /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
     979                 :    Set the class used in getIterator. */
     980                 : SPL_METHOD(Array, setIteratorClass)
     981               4 : {
     982               4 :         zval *object = getThis();
     983               4 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
     984               4 :         zend_class_entry * ce_get_iterator = spl_ce_Iterator;
     985                 : 
     986               4 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
     987               2 :                 php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
     988               2 :                 return;
     989                 :         }
     990                 : 
     991               2 :         intern->ce_get_iterator = ce_get_iterator;
     992                 : }
     993                 : /* }}} */
     994                 : 
     995                 : /* {{{ proto string ArrayObject::getIteratorClass()
     996                 :    Get the class used in getIterator. */
     997                 : SPL_METHOD(Array, getIteratorClass)
     998               4 : {
     999               4 :         zval *object = getThis();
    1000               4 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1001                 : 
    1002               4 :         RETURN_STRING(intern->ce_get_iterator->name, 1);
    1003                 : }
    1004                 : /* }}} */
    1005                 : 
    1006                 : /* {{{ proto int ArrayObject::getFlags()
    1007                 :    Get flags */
    1008                 : SPL_METHOD(Array, getFlags)
    1009              30 : {
    1010              30 :         zval *object = getThis();
    1011              30 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1012                 :         
    1013              30 :         RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
    1014                 : }
    1015                 : /* }}} */
    1016                 : 
    1017                 : /* {{{ proto void ArrayObject::setFlags(int flags)
    1018                 :    Set flags */
    1019                 : SPL_METHOD(Array, setFlags)
    1020              16 : {
    1021              16 :         zval *object = getThis();
    1022              16 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1023              16 :         long ar_flags = 0;
    1024                 : 
    1025              16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
    1026               0 :                 return;
    1027                 :         }
    1028                 :         
    1029              16 :         intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
    1030                 : }
    1031                 : /* }}} */
    1032                 : 
    1033                 : /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
    1034                 :    Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
    1035                 : SPL_METHOD(Array, exchangeArray)
    1036               5 : {
    1037               5 :         zval *object = getThis(), *tmp, **array;
    1038               5 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1039                 : 
    1040               5 :         array_init(return_value);
    1041               5 :         zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
    1042                 :         
    1043               5 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
    1044               1 :                 return;
    1045                 :         }
    1046               6 :         if (Z_TYPE_PP(array) == IS_OBJECT && intern == (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC)) {
    1047               2 :                 zval_ptr_dtor(&intern->array);
    1048               2 :                 array = &object;
    1049               2 :                 intern->array = object;
    1050               2 :         } else if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
    1051               0 :                 spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
    1052               0 :                 zval_ptr_dtor(&intern->array);
    1053               0 :                 intern->array = other->array;
    1054                 :         } else {
    1055               2 :                 if (Z_TYPE_PP(array) != IS_OBJECT && !HASH_OF(*array)) {
    1056               1 :                         zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
    1057               1 :                         return;
    1058                 :                 }
    1059               1 :                 zval_ptr_dtor(&intern->array);
    1060               1 :                 intern->array = *array;
    1061               1 :                 intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
    1062                 :         }
    1063               3 :         if (object == *array) {
    1064               2 :                 intern->ar_flags |= SPL_ARRAY_IS_SELF;
    1065                 :         } else {
    1066               1 :                 intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
    1067                 :         }
    1068               3 :         ZVAL_ADDREF(intern->array);
    1069                 : 
    1070               3 :         spl_array_rewind(intern TSRMLS_CC);
    1071                 : }
    1072                 : /* }}} */
    1073                 : 
    1074                 : /* {{{ proto ArrayIterator ArrayObject::getIterator()
    1075                 :    Create a new iterator from a ArrayObject instance */
    1076                 : SPL_METHOD(Array, getIterator)
    1077              65 : {
    1078              65 :         zval *object = getThis();
    1079              65 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1080                 :         spl_array_object *iterator;
    1081              65 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1082                 : 
    1083              65 :         if (!aht) {
    1084               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1085               0 :                 return;
    1086                 :         }
    1087                 : 
    1088              65 :         return_value->type = IS_OBJECT;
    1089              65 :         return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
    1090              65 :         return_value->refcount = 1;
    1091              65 :         return_value->is_ref = 1;
    1092                 : }
    1093                 : /* }}} */
    1094                 : 
    1095                 : /* {{{ proto void ArrayIterator::rewind()
    1096                 :    Rewind array back to the start */
    1097                 : SPL_METHOD(Array, rewind)
    1098              95 : {
    1099              95 :         zval *object = getThis();
    1100              95 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1101                 : 
    1102              95 :         spl_array_rewind(intern TSRMLS_CC);
    1103              95 : }
    1104                 : /* }}} */
    1105                 : 
    1106                 : /* {{{ proto void ArrayIterator::seek(int $position)
    1107                 :  Seek to position. */
    1108                 : SPL_METHOD(Array, seek)
    1109              27 : {
    1110                 :         long opos, position;
    1111              27 :         zval *object = getThis();
    1112              27 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1113              27 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1114                 :         int result;
    1115                 : 
    1116              27 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
    1117               0 :                 return;
    1118                 :         }
    1119                 : 
    1120              27 :         if (!aht) {
    1121               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1122               0 :                 return;
    1123                 :         }
    1124                 : 
    1125              27 :         opos = position;
    1126                 : 
    1127              27 :         if (position >= 0) { /* negative values are not supported */
    1128              26 :                 spl_array_rewind(intern TSRMLS_CC);
    1129              26 :                 result = SUCCESS;
    1130                 :                 
    1131             112 :                 while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
    1132                 :         
    1133              26 :                 if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
    1134              25 :                         return; /* ok */
    1135                 :                 }
    1136                 :         }
    1137               2 :         zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
    1138                 : } /* }}} */
    1139                 : 
    1140                 : int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
    1141              22 : {
    1142              22 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1143              22 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1144                 :         HashPosition pos;
    1145                 : 
    1146              22 :         if (!aht) {
    1147               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1148               0 :                 *count = 0;
    1149               0 :                 return FAILURE;
    1150                 :         }
    1151                 : 
    1152              22 :         if (Z_TYPE_P(intern->array) == IS_OBJECT) {
    1153                 :                 /* We need to store the 'pos' since we'll modify it in the functions 
    1154                 :                  * we're going to call and which do not support 'pos' as parameter. */
    1155               5 :                 pos = intern->pos;
    1156               5 :                 *count = 0;
    1157               5 :                 spl_array_rewind(intern TSRMLS_CC);
    1158              25 :                 while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
    1159              15 :                         (*count)++;
    1160                 :                 }
    1161               5 :                 intern->pos = pos;
    1162               5 :                 return SUCCESS;
    1163                 :         } else {
    1164              17 :                 *count = zend_hash_num_elements(aht);
    1165              17 :                 return SUCCESS;
    1166                 :         }
    1167                 : } /* }}} */
    1168                 : 
    1169                 : /* {{{ proto int ArrayObject::count()
    1170                 :        proto int ArrayIterator::count()
    1171                 :  Return the number of elements in the Iterator. */
    1172                 : SPL_METHOD(Array, count)
    1173              22 : {
    1174                 :         long count;
    1175                 : 
    1176              22 :         spl_array_object_count_elements(getThis(), &count TSRMLS_CC);
    1177              22 :         RETURN_LONG(count);
    1178                 : } /* }}} */
    1179                 : 
    1180                 : static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
    1181              17 : {
    1182              17 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
    1183              17 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1184                 :         zval tmp, *arg;
    1185              17 :         zval *retval_ptr = NULL;
    1186                 :         
    1187              17 :         INIT_PZVAL(&tmp);
    1188              17 :         Z_TYPE(tmp) = IS_ARRAY;
    1189              17 :         Z_ARRVAL(tmp) = aht;
    1190                 :         
    1191              17 :         if (use_arg) {
    1192               6 :                 if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
    1193               4 :                         zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
    1194               4 :                         return;
    1195                 :                 }
    1196               2 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, &tmp, arg TSRMLS_CC);
    1197                 :         } else {
    1198              11 :                 zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, &tmp, NULL TSRMLS_CC);
    1199                 :         }
    1200              13 :         if (retval_ptr) {
    1201              13 :                 COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
    1202                 :         }
    1203                 : }
    1204                 : 
    1205                 : #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
    1206                 : SPL_METHOD(cname, fname) \
    1207                 : { \
    1208                 :         spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
    1209                 : }
    1210                 : 
    1211                 : /* {{{ proto int ArrayObject::asort()
    1212                 :        proto int ArrayIterator::asort()
    1213                 :  Sort the entries by values. */
    1214               4 : SPL_ARRAY_METHOD(Array, asort, 0)
    1215                 : 
    1216                 : /* {{{ proto int ArrayObject::ksort()
    1217                 :        proto int ArrayIterator::ksort()
    1218                 :  Sort the entries by key. */
    1219               3 : SPL_ARRAY_METHOD(Array, ksort, 0)
    1220                 : 
    1221                 : /* {{{ proto int ArrayObject::uasort(callback cmp_function)
    1222                 :        proto int ArrayIterator::uasort(callback cmp_function)
    1223                 :  Sort the entries by values user defined function. */
    1224               3 : SPL_ARRAY_METHOD(Array, uasort, 1)
    1225                 : 
    1226                 : /* {{{ proto int ArrayObject::uksort(callback cmp_function)
    1227                 :        proto int ArrayIterator::uksort(callback cmp_function)
    1228                 :  Sort the entries by key using user defined function. */
    1229               3 : SPL_ARRAY_METHOD(Array, uksort, 1)
    1230                 : 
    1231                 : /* {{{ proto int ArrayObject::natsort()
    1232                 :        proto int ArrayIterator::natsort()
    1233                 :  Sort the entries by values using "natural order" algorithm. */
    1234               2 : SPL_ARRAY_METHOD(Array, natsort, 0)
    1235                 : 
    1236                 : /* {{{ proto int ArrayObject::natcasesort()
    1237                 :        proto int ArrayIterator::natcasesort()
    1238                 :  Sort the entries by key using case insensitive "natural order" algorithm. */
    1239               2 : SPL_ARRAY_METHOD(Array, natcasesort, 0)
    1240                 : 
    1241                 : /* {{{ proto mixed|NULL ArrayIterator::current()
    1242                 :    Return current array entry */
    1243                 : SPL_METHOD(Array, current)
    1244             188 : {
    1245             188 :         zval *object = getThis();
    1246             188 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1247                 :         zval **entry;
    1248             188 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1249                 : 
    1250             188 :         if (!aht) {
    1251               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1252               0 :                 return;
    1253                 :         }
    1254                 : 
    1255             188 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1256               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1257               0 :                 return;
    1258                 :         }
    1259                 : 
    1260             188 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1261               0 :                 return;
    1262                 :         }
    1263             188 :         RETVAL_ZVAL(*entry, 1, 0);
    1264                 : }
    1265                 : /* }}} */
    1266                 : 
    1267                 : /* {{{ proto mixed|NULL ArrayIterator::key()
    1268                 :    Return current array key */
    1269                 : SPL_METHOD(Array, key)
    1270             141 : {
    1271             141 :         spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
    1272             141 : }
    1273                 : 
    1274                 : void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
    1275             147 : {
    1276             147 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1277                 :         char *string_key;
    1278                 :         uint string_length;
    1279                 :         ulong num_key;
    1280             147 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1281                 : 
    1282             147 :         if (!aht) {
    1283               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1284               0 :                 return;
    1285                 :         }
    1286                 : 
    1287             147 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1288               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1289               0 :                 return;
    1290                 :         }
    1291                 : 
    1292             147 :         switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
    1293                 :                 case HASH_KEY_IS_STRING:
    1294              13 :                         RETVAL_STRINGL(string_key, string_length - 1, 0);
    1295              13 :                         break;
    1296                 :                 case HASH_KEY_IS_LONG:
    1297             134 :                         RETVAL_LONG(num_key);
    1298             134 :                         break;
    1299                 :                 case HASH_KEY_NON_EXISTANT:
    1300               0 :                         return;
    1301                 :         }
    1302                 : }
    1303                 : /* }}} */
    1304                 : 
    1305                 : /* {{{ proto void ArrayIterator::next()
    1306                 :    Move to next entry */
    1307                 : SPL_METHOD(Array, next)
    1308             168 : {
    1309             168 :         zval *object = getThis();
    1310             168 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1311             168 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1312                 : 
    1313             168 :         if (!aht) {
    1314               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1315               0 :                 return;
    1316                 :         }
    1317                 : 
    1318             168 :         spl_array_next(intern TSRMLS_CC);
    1319                 : }
    1320                 : /* }}} */
    1321                 : 
    1322                 : /* {{{ proto bool ArrayIterator::valid()
    1323                 :    Check whether array contains more entries */
    1324                 : SPL_METHOD(Array, valid)
    1325             430 : {
    1326             430 :         zval *object = getThis();
    1327             430 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1328             430 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1329                 : 
    1330             430 :         if (!aht) {
    1331               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1332               0 :                 return;
    1333                 :         }
    1334                 : 
    1335             430 :         if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1336               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1337               0 :                 RETURN_FALSE;
    1338                 :         } else {
    1339             430 :                 RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
    1340                 :         }
    1341                 : }
    1342                 : /* }}} */
    1343                 : 
    1344                 : /* {{{ proto bool RecursiveArrayIterator::hasChildren()
    1345                 :    Check whether current element has children (e.g. is an array) */
    1346                 : SPL_METHOD(Array, hasChildren)
    1347             491 : {
    1348             491 :         zval *object = getThis(), **entry;
    1349             491 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1350             491 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1351                 :         
    1352             491 :         if (!aht) {
    1353               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1354               0 :                 RETURN_FALSE;
    1355                 :         }
    1356                 : 
    1357             491 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1358               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1359               0 :                 RETURN_FALSE;
    1360                 :         }
    1361                 : 
    1362             491 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1363               9 :                 RETURN_FALSE;
    1364                 :         }
    1365                 : 
    1366             482 :         RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT);
    1367                 : }
    1368                 : /* }}} */
    1369                 : 
    1370                 : /* {{{ proto object RecursiveArrayIterator::getChildren()
    1371                 :    Create a sub iterator for the current element (same class as $this) */
    1372                 : SPL_METHOD(Array, getChildren)
    1373             108 : {
    1374             108 :         zval *object = getThis(), **entry, *flags;
    1375             108 :         spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
    1376             108 :         HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
    1377                 : 
    1378             108 :         if (!aht) {
    1379               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
    1380               0 :                 return;
    1381                 :         }
    1382                 : 
    1383             108 :         if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
    1384               0 :                 php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
    1385               0 :                 return;
    1386                 :         }
    1387                 : 
    1388             108 :         if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
    1389               0 :                 return;
    1390                 :         }
    1391                 : 
    1392             108 :         if (Z_TYPE_PP(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
    1393               0 :                 RETURN_ZVAL(*entry, 0, 0);
    1394                 :         }
    1395                 : 
    1396             108 :   MAKE_STD_ZVAL(flags);
    1397             108 :   ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER);
    1398             108 :         spl_instantiate_arg_ex2(intern->std.ce, &return_value, 0, *entry, flags TSRMLS_CC);
    1399             108 :         zval_ptr_dtor(&flags);
    1400                 : }
    1401                 : /* }}} */
    1402                 : 
    1403                 : static
    1404                 : ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
    1405                 :         ZEND_ARG_INFO(0, array)
    1406                 : ZEND_END_ARG_INFO()
    1407                 : 
    1408                 : static
    1409                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
    1410                 :         ZEND_ARG_INFO(0, index)
    1411                 : ZEND_END_ARG_INFO()
    1412                 : 
    1413                 : static
    1414                 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
    1415                 :         ZEND_ARG_INFO(0, index)
    1416                 :         ZEND_ARG_INFO(0, newval)
    1417                 : ZEND_END_ARG_INFO()
    1418                 : 
    1419                 : static
    1420                 : ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
    1421                 :         ZEND_ARG_INFO(0, value)
    1422                 : ZEND_END_ARG_INFO()
    1423                 : 
    1424                 : static
    1425                 : ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
    1426                 :         ZEND_ARG_INFO(0, position)
    1427                 : ZEND_END_ARG_INFO()
    1428                 : 
    1429                 : static
    1430                 : ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
    1431                 :         ZEND_ARG_INFO(0, array)
    1432                 : ZEND_END_ARG_INFO()
    1433                 : 
    1434                 : static
    1435                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
    1436                 :         ZEND_ARG_INFO(0, flags)
    1437                 : ZEND_END_ARG_INFO()
    1438                 : 
    1439                 : static
    1440                 : ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
    1441                 :         ZEND_ARG_INFO(0, iteratorClass)
    1442                 : ZEND_END_ARG_INFO()
    1443                 : 
    1444                 : static
    1445                 : ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
    1446                 :         ZEND_ARG_INFO(0, cmp_function )
    1447                 : ZEND_END_ARG_INFO();
    1448                 : 
    1449                 : static zend_function_entry spl_funcs_ArrayObject[] = {
    1450                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1451                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1452                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1453                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1454                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1455                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1456                 :         SPL_ME(Array, getArrayCopy,     NULL,                           ZEND_ACC_PUBLIC)
    1457                 :         SPL_ME(Array, count,            NULL,                           ZEND_ACC_PUBLIC)
    1458                 :         SPL_ME(Array, getFlags,         NULL,                           ZEND_ACC_PUBLIC)
    1459                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1460                 :         SPL_ME(Array, asort,            NULL,                           ZEND_ACC_PUBLIC)
    1461                 :         SPL_ME(Array, ksort,            NULL,                           ZEND_ACC_PUBLIC)
    1462                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1463                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1464                 :         SPL_ME(Array, natsort,          NULL,                           ZEND_ACC_PUBLIC)
    1465                 :         SPL_ME(Array, natcasesort,      NULL,                           ZEND_ACC_PUBLIC)
    1466                 :         /* ArrayObject specific */
    1467                 :         SPL_ME(Array, getIterator,      NULL,                           ZEND_ACC_PUBLIC)
    1468                 :         SPL_ME(Array, exchangeArray,    arginfo_array_exchangeArray,    ZEND_ACC_PUBLIC)
    1469                 :         SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
    1470                 :         SPL_ME(Array, getIteratorClass, NULL,                           ZEND_ACC_PUBLIC)
    1471                 :         {NULL, NULL, NULL}
    1472                 : };
    1473                 : 
    1474                 : static zend_function_entry spl_funcs_ArrayIterator[] = {
    1475                 :         SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
    1476                 :         SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1477                 :         SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1478                 :         SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
    1479                 :         SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
    1480                 :         SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
    1481                 :         SPL_ME(Array, getArrayCopy,     NULL,                           ZEND_ACC_PUBLIC)
    1482                 :         SPL_ME(Array, count,            NULL,                           ZEND_ACC_PUBLIC)
    1483                 :         SPL_ME(Array, getFlags,         NULL,                           ZEND_ACC_PUBLIC)
    1484                 :         SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
    1485                 :         SPL_ME(Array, asort,            NULL,                           ZEND_ACC_PUBLIC)
    1486                 :         SPL_ME(Array, ksort,            NULL,                           ZEND_ACC_PUBLIC)
    1487                 :         SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1488                 :         SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
    1489                 :         SPL_ME(Array, natsort,          NULL,                           ZEND_ACC_PUBLIC)
    1490                 :         SPL_ME(Array, natcasesort,      NULL,                           ZEND_ACC_PUBLIC)
    1491                 :         /* ArrayIterator specific */
    1492                 :         SPL_ME(Array, rewind,           NULL,                           ZEND_ACC_PUBLIC)
    1493                 :         SPL_ME(Array, current,          NULL,                           ZEND_ACC_PUBLIC)
    1494                 :         SPL_ME(Array, key,              NULL,                           ZEND_ACC_PUBLIC)
    1495                 :         SPL_ME(Array, next,             NULL,                           ZEND_ACC_PUBLIC)
    1496                 :         SPL_ME(Array, valid,            NULL,                           ZEND_ACC_PUBLIC)
    1497                 :         SPL_ME(Array, seek,             arginfo_array_seek,             ZEND_ACC_PUBLIC)
    1498                 :         {NULL, NULL, NULL}
    1499                 : };
    1500                 : 
    1501                 : static zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
    1502                 :         SPL_ME(Array, hasChildren,   NULL, ZEND_ACC_PUBLIC)
    1503                 :         SPL_ME(Array, getChildren,   NULL, ZEND_ACC_PUBLIC)
    1504                 :         {NULL, NULL, NULL}
    1505                 : };
    1506                 : 
    1507                 : /* {{{ PHP_MINIT_FUNCTION(spl_array) */
    1508                 : PHP_MINIT_FUNCTION(spl_array)
    1509           13565 : {
    1510           13565 :         REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
    1511           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
    1512           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
    1513           13565 :         memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    1514                 : 
    1515           13565 :         spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
    1516           13565 :         spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
    1517           13565 :         spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
    1518           13565 :         spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
    1519           13565 :         spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
    1520           13565 :         spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
    1521                 : 
    1522           13565 :         spl_handler_ArrayObject.get_properties = spl_array_get_properties;
    1523           13565 :         spl_handler_ArrayObject.read_property = spl_array_read_property;
    1524           13565 :         spl_handler_ArrayObject.write_property = spl_array_write_property;
    1525           13565 :         spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
    1526           13565 :         spl_handler_ArrayObject.has_property = spl_array_has_property;
    1527           13565 :         spl_handler_ArrayObject.unset_property = spl_array_unset_property;
    1528                 : 
    1529           13565 :         REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
    1530           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
    1531           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
    1532           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
    1533           13565 :         memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
    1534           13565 :         spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
    1535                 :         
    1536           13565 :         REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
    1537           13565 :         REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
    1538           13565 :         spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
    1539                 : 
    1540           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
    1541           13565 :         REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
    1542                 : 
    1543           13565 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1544           13565 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1545                 : 
    1546           13565 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
    1547           13565 :         REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
    1548           13565 :         return SUCCESS;
    1549                 : }
    1550                 : /* }}} */
    1551                 : 
    1552                 : /*
    1553                 :  * Local variables:
    1554                 :  * tab-width: 4
    1555                 :  * c-basic-offset: 4
    1556                 :  * End:
    1557                 :  * vim600: fdm=marker
    1558                 :  * vim: noet sw=4 ts=4
    1559                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:20 +0000 (5 days ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.