Back to index

php5  5.3.10
spl_array.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Marcus Boerger <helly@php.net>                              |
00016    +----------------------------------------------------------------------+
00017  */
00018 
00019 /* $Id: spl_array.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 # include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 #include "php_ini.h"
00027 #include "ext/standard/info.h"
00028 #include "ext/standard/php_var.h"
00029 #include "ext/standard/php_smart_str.h"
00030 #include "zend_interfaces.h"
00031 #include "zend_exceptions.h"
00032 
00033 #include "php_spl.h"
00034 #include "spl_functions.h"
00035 #include "spl_engine.h"
00036 #include "spl_iterators.h"
00037 #include "spl_array.h"
00038 #include "spl_exceptions.h"
00039 
00040 zend_object_handlers spl_handler_ArrayObject;
00041 PHPAPI zend_class_entry  *spl_ce_ArrayObject;
00042 
00043 zend_object_handlers spl_handler_ArrayIterator;
00044 PHPAPI zend_class_entry  *spl_ce_ArrayIterator;
00045 PHPAPI zend_class_entry  *spl_ce_RecursiveArrayIterator;
00046 
00047 #define SPL_ARRAY_STD_PROP_LIST      0x00000001
00048 #define SPL_ARRAY_ARRAY_AS_PROPS     0x00000002
00049 #define SPL_ARRAY_CHILD_ARRAYS_ONLY  0x00000004
00050 #define SPL_ARRAY_OVERLOADED_REWIND  0x00010000
00051 #define SPL_ARRAY_OVERLOADED_VALID   0x00020000
00052 #define SPL_ARRAY_OVERLOADED_KEY     0x00040000
00053 #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
00054 #define SPL_ARRAY_OVERLOADED_NEXT    0x00100000
00055 #define SPL_ARRAY_IS_REF             0x01000000
00056 #define SPL_ARRAY_IS_SELF            0x02000000
00057 #define SPL_ARRAY_USE_OTHER          0x04000000
00058 #define SPL_ARRAY_INT_MASK           0xFFFF0000
00059 #define SPL_ARRAY_CLONE_MASK         0x0300FFFF
00060 
00061 typedef struct _spl_array_object {
00062        zend_object            std;
00063        zval                   *array;
00064        zval                   *retval;
00065        HashPosition           pos;
00066        ulong                  pos_h;
00067        int                    ar_flags;
00068        int                    is_self;
00069        zend_function          *fptr_offset_get;
00070        zend_function          *fptr_offset_set;
00071        zend_function          *fptr_offset_has;
00072        zend_function          *fptr_offset_del;
00073        zend_function          *fptr_count;
00074        zend_function          *fptr_serialize;
00075        zend_function          *fptr_unserialize;
00076        zend_class_entry       *ce_get_iterator;
00077        php_serialize_data_t   *serialize_data;
00078        php_unserialize_data_t *unserialize_data;
00079        HashTable              *debug_info;
00080        unsigned char           nApplyCount;
00081 } spl_array_object;
00082 
00083 static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
00084        if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
00085               return intern->std.properties;
00086        } 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) {
00087               spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
00088               return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
00089        } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
00090               return intern->std.properties;
00091        } else {
00092               return HASH_OF(intern->array);
00093        }
00094 } /* }}} */
00095 
00096 static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
00097 
00098 static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
00099 {
00100        Bucket *pos = intern->pos;
00101        if (pos != NULL) {
00102               intern->pos_h = pos->h;
00103        }
00104 } /* }}} */
00105 
00106 static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
00107 {
00108        intern->pos = pos;
00109        spl_array_update_pos(intern);
00110 } /* }}} */
00111 
00112 SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
00113 {
00114        Bucket *p;
00115 
00116 /*     IS_CONSISTENT(ht);*/
00117 
00118 /*     HASH_PROTECT_RECURSION(ht);*/
00119        p = ht->arBuckets[intern->pos_h & ht->nTableMask];
00120        while (p != NULL) {
00121               if (p == intern->pos) {
00122                      return SUCCESS;
00123               }
00124               p = p->pNext;
00125        }
00126 /*     HASH_UNPROTECT_RECURSION(ht); */
00127        spl_array_rewind(intern TSRMLS_CC);
00128        return FAILURE;
00129 
00130 } /* }}} */
00131 
00132 SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
00133 {
00134        HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00135        return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
00136 }
00137 /* }}} */
00138 
00139 /* {{{ spl_array_object_free_storage */
00140 static void spl_array_object_free_storage(void *object TSRMLS_DC)
00141 {
00142        spl_array_object *intern = (spl_array_object *)object;
00143 
00144        zend_object_std_dtor(&intern->std TSRMLS_CC);
00145 
00146        zval_ptr_dtor(&intern->array);
00147        zval_ptr_dtor(&intern->retval);
00148 
00149        if (intern->debug_info != NULL) {
00150               zend_hash_destroy(intern->debug_info);
00151               efree(intern->debug_info);
00152        }
00153 
00154        efree(object);
00155 }
00156 /* }}} */
00157 
00158 zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
00159 int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
00160 int spl_array_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
00161 
00162 /* {{{ spl_array_object_new_ex */
00163 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)
00164 {
00165        zend_object_value retval;
00166        spl_array_object *intern;
00167        zval *tmp;
00168        zend_class_entry * parent = class_type;
00169        int inherited = 0;
00170 
00171        intern = emalloc(sizeof(spl_array_object));
00172        memset(intern, 0, sizeof(spl_array_object));
00173        *obj = intern;
00174        ALLOC_INIT_ZVAL(intern->retval);
00175 
00176        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
00177        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00178 
00179        intern->ar_flags = 0;
00180        intern->serialize_data   = NULL;
00181        intern->unserialize_data = NULL;
00182        intern->debug_info       = NULL;
00183        intern->ce_get_iterator = spl_ce_ArrayIterator;
00184        if (orig) {
00185               spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
00186 
00187               intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
00188               intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
00189               intern->ce_get_iterator = other->ce_get_iterator;
00190               if (clone_orig) {
00191                      intern->array = other->array;
00192                      if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
00193                             MAKE_STD_ZVAL(intern->array);
00194                             array_init(intern->array);
00195                             zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
00196                      }
00197                      if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
00198                             Z_ADDREF_P(other->array);
00199                      }
00200               } else {
00201                      intern->array = orig;
00202                      Z_ADDREF_P(intern->array);
00203                      intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
00204               }
00205        } else {
00206               MAKE_STD_ZVAL(intern->array);
00207               array_init(intern->array);
00208               intern->ar_flags &= ~SPL_ARRAY_IS_REF;
00209        }
00210 
00211        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);
00212        while (parent) {
00213               if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
00214                      retval.handlers = &spl_handler_ArrayIterator;
00215                      class_type->get_iterator = spl_array_get_iterator;
00216                      break;
00217               } else if (parent == spl_ce_ArrayObject) {
00218                      retval.handlers = &spl_handler_ArrayObject;
00219                      break;
00220               }
00221               parent = parent->parent;
00222               inherited = 1;
00223        }
00224        if (!parent) { /* this must never happen */
00225               php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
00226        }
00227        if (inherited) {
00228               zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
00229               if (intern->fptr_offset_get->common.scope == parent) {
00230                      intern->fptr_offset_get = NULL;
00231               }
00232               zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
00233               if (intern->fptr_offset_set->common.scope == parent) {
00234                      intern->fptr_offset_set = NULL;
00235               }
00236               zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
00237               if (intern->fptr_offset_has->common.scope == parent) {
00238                      intern->fptr_offset_has = NULL;
00239               }
00240               zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
00241               if (intern->fptr_offset_del->common.scope == parent) {
00242                      intern->fptr_offset_del = NULL;
00243               }
00244               zend_hash_find(&class_type->function_table, "count",        sizeof("count"),        (void **) &intern->fptr_count);
00245               if (intern->fptr_count->common.scope == parent) {
00246                      intern->fptr_count = NULL;
00247               }
00248               zend_hash_find(&class_type->function_table, "serialize",    sizeof("serialize"),    (void **) &intern->fptr_serialize);
00249               if (intern->fptr_serialize->common.scope == parent) {
00250                      intern->fptr_serialize = NULL;
00251               }
00252               zend_hash_find(&class_type->function_table, "unserialize",  sizeof("unserialize"),  (void **) &intern->fptr_unserialize);
00253               if (intern->fptr_unserialize->common.scope == parent) {
00254                      intern->fptr_unserialize = NULL;
00255               }
00256        }
00257        /* Cache iterator functions if ArrayIterator or derived. Check current's */
00258        /* cache since only current is always required */
00259        if (retval.handlers == &spl_handler_ArrayIterator) {
00260               if (!class_type->iterator_funcs.zf_current) {
00261                      zend_hash_find(&class_type->function_table, "rewind",  sizeof("rewind"),  (void **) &class_type->iterator_funcs.zf_rewind);
00262                      zend_hash_find(&class_type->function_table, "valid",   sizeof("valid"),   (void **) &class_type->iterator_funcs.zf_valid);
00263                      zend_hash_find(&class_type->function_table, "key",     sizeof("key"),     (void **) &class_type->iterator_funcs.zf_key);
00264                      zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
00265                      zend_hash_find(&class_type->function_table, "next",    sizeof("next"),    (void **) &class_type->iterator_funcs.zf_next);
00266               }
00267               if (inherited) {
00268                      if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
00269                      if (class_type->iterator_funcs.zf_valid->common.scope   != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
00270                      if (class_type->iterator_funcs.zf_key->common.scope     != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
00271                      if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
00272                      if (class_type->iterator_funcs.zf_next->common.scope    != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
00273               }
00274        }
00275 
00276        spl_array_rewind(intern TSRMLS_CC);
00277        return retval;
00278 }
00279 /* }}} */
00280 
00281 /* {{{ spl_array_object_new */
00282 static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
00283 {
00284        spl_array_object *tmp;
00285        return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
00286 }
00287 /* }}} */
00288 
00289 /* {{{ spl_array_object_clone */
00290 static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
00291 {
00292        zend_object_value new_obj_val;
00293        zend_object *old_object;
00294        zend_object *new_object;
00295        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
00296        spl_array_object *intern;
00297 
00298        old_object = zend_objects_get_address(zobject TSRMLS_CC);
00299        new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
00300        new_object = &intern->std;
00301 
00302        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
00303 
00304        return new_obj_val;
00305 }
00306 /* }}} */
00307 
00308 static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
00309 {
00310        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00311        zval **retval;
00312        long index;
00313        HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00314 
00315 /*  We cannot get the pointer pointer so we don't allow it here for now
00316        if (check_inherited && intern->fptr_offset_get) {
00317               return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
00318        }*/
00319 
00320        if (!offset) {
00321               return &EG(uninitialized_zval_ptr);
00322        }
00323        
00324        if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
00325               zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00326               return &EG(uninitialized_zval_ptr);;
00327        }
00328 
00329        switch(Z_TYPE_P(offset)) {
00330        case IS_STRING:
00331               if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
00332                      if (type == BP_VAR_W || type == BP_VAR_RW) {
00333                             zval *value;
00334                             ALLOC_INIT_ZVAL(value);
00335                             zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
00336                             zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval);
00337                             return retval;
00338                      } else {
00339                             zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(offset));
00340                             return &EG(uninitialized_zval_ptr);
00341                      }
00342               } else {
00343                      return retval;
00344               }
00345        case IS_DOUBLE:
00346        case IS_RESOURCE:
00347        case IS_BOOL: 
00348        case IS_LONG: 
00349               if (offset->type == IS_DOUBLE) {
00350                      index = (long)Z_DVAL_P(offset);
00351               } else {
00352                      index = Z_LVAL_P(offset);
00353               }
00354               if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
00355                      if (type == BP_VAR_W || type == BP_VAR_RW) {
00356                             zval *value;
00357                             ALLOC_INIT_ZVAL(value);
00358                             zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
00359                             zend_hash_index_find(ht, index, (void **) &retval);
00360                             return retval;
00361                      } else {
00362                             zend_error(E_NOTICE, "Undefined offset:  %ld", index);
00363                             return &EG(uninitialized_zval_ptr);
00364                      }
00365               } else {
00366                      return retval;
00367               }
00368               break;
00369        default:
00370               zend_error(E_WARNING, "Illegal offset type");
00371               return &EG(uninitialized_zval_ptr);
00372        }
00373 } /* }}} */
00374 
00375 static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
00376 {
00377        zval **ret;
00378 
00379        if (check_inherited) {
00380               spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00381               if (intern->fptr_offset_get) {
00382                      zval *rv;
00383                      SEPARATE_ARG_IF_REF(offset);
00384                      zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset); 
00385                      zval_ptr_dtor(&offset);
00386                      if (rv) {
00387                             zval_ptr_dtor(&intern->retval);
00388                             MAKE_STD_ZVAL(intern->retval);
00389                             ZVAL_ZVAL(intern->retval, rv, 1, 1);
00390                             return intern->retval;
00391                      }
00392                      return EG(uninitialized_zval_ptr);
00393               }
00394        }
00395        ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
00396 
00397        /* When in a write context,
00398         * ZE has to be fooled into thinking this is in a reference set
00399         * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
00400        if ((type == BP_VAR_W || type == BP_VAR_RW) && !Z_ISREF_PP(ret)) {
00401               if (Z_REFCOUNT_PP(ret) > 1) {
00402                      zval *newval;
00403 
00404                      /* Separate */
00405                      MAKE_STD_ZVAL(newval);
00406                      *newval = **ret;
00407                      zval_copy_ctor(newval);
00408                      Z_SET_REFCOUNT_P(newval, 1);
00409 
00410                      /* Replace */
00411                      Z_DELREF_PP(ret);
00412                      *ret = newval;
00413               }
00414 
00415               Z_SET_ISREF_PP(ret);
00416        }
00417 
00418        return *ret;
00419 } /* }}} */
00420 
00421 static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
00422 {
00423        return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
00424 } /* }}} */
00425 
00426 static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
00427 {
00428        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00429        long index;
00430        HashTable *ht;
00431 
00432        if (check_inherited && intern->fptr_offset_set) {
00433               if (!offset) {
00434                      ALLOC_INIT_ZVAL(offset);
00435               } else {
00436                      SEPARATE_ARG_IF_REF(offset);
00437               }
00438               zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
00439               zval_ptr_dtor(&offset);
00440               return;
00441        }
00442        
00443        if (!offset) {
00444               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00445               if (ht->nApplyCount > 0) {
00446                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00447                      return;
00448               }
00449               Z_ADDREF_P(value);
00450               zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
00451               return;
00452        }
00453        switch(Z_TYPE_P(offset)) {
00454        case IS_STRING:
00455               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00456               if (ht->nApplyCount > 0) {
00457                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00458                      return;
00459               }
00460               Z_ADDREF_P(value);
00461               zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
00462               return;
00463        case IS_DOUBLE:
00464        case IS_RESOURCE:
00465        case IS_BOOL: 
00466        case IS_LONG: 
00467               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00468               if (ht->nApplyCount > 0) {
00469                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00470                      return;
00471               }
00472               if (offset->type == IS_DOUBLE) {
00473                      index = (long)Z_DVAL_P(offset);
00474               } else {
00475                      index = Z_LVAL_P(offset);
00476               }
00477               Z_ADDREF_P(value);
00478               zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
00479               return;
00480        case IS_NULL:
00481               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00482               if (ht->nApplyCount > 0) {
00483                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00484                      return;
00485               }
00486               Z_ADDREF_P(value);
00487               zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
00488               return;
00489        default:
00490               zend_error(E_WARNING, "Illegal offset type");
00491               return;
00492        }
00493 } /* }}} */
00494 
00495 static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
00496 {
00497        spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
00498 } /* }}} */
00499 
00500 static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
00501 {
00502        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00503        long index;
00504        HashTable *ht;
00505 
00506        if (check_inherited && intern->fptr_offset_del) {
00507               SEPARATE_ARG_IF_REF(offset);
00508               zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
00509               zval_ptr_dtor(&offset);
00510               return;
00511        }
00512 
00513        switch(Z_TYPE_P(offset)) {
00514        case IS_STRING:
00515               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00516               if (ht->nApplyCount > 0) {
00517                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00518                      return;
00519               }
00520               if (ht == &EG(symbol_table)) {
00521                      if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
00522                             zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
00523                      }
00524               } else {
00525                      if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
00526                             zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
00527                      }
00528               }
00529               break;
00530        case IS_DOUBLE:
00531        case IS_RESOURCE:
00532        case IS_BOOL: 
00533        case IS_LONG: 
00534               if (offset->type == IS_DOUBLE) {
00535                      index = (long)Z_DVAL_P(offset);
00536               } else {
00537                      index = Z_LVAL_P(offset);
00538               }
00539               ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00540               if (ht->nApplyCount > 0) {
00541                      zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
00542                      return;
00543               }
00544               if (zend_hash_index_del(ht, index) == FAILURE) {
00545                      zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
00546               }
00547               break;
00548        default:
00549               zend_error(E_WARNING, "Illegal offset type");
00550               return;
00551        }
00552        spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
00553 } /* }}} */
00554 
00555 static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
00556 {
00557        spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
00558 } /* }}} */
00559 
00560 static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
00561 {
00562        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00563        long index;
00564        zval *rv, **tmp;
00565 
00566        if (check_inherited && intern->fptr_offset_has) {
00567               SEPARATE_ARG_IF_REF(offset);
00568               zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
00569               zval_ptr_dtor(&offset);
00570               if (rv && zend_is_true(rv)) {
00571                      zval_ptr_dtor(&rv);
00572                      return 1;
00573               }
00574               if (rv) {
00575                      zval_ptr_dtor(&rv);
00576               }
00577               return 0;
00578        }
00579        
00580        switch(Z_TYPE_P(offset)) {
00581        case IS_STRING:
00582               if (check_empty) {
00583                      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) {
00584                             switch (check_empty) {
00585                                    case 0:
00586                                           return Z_TYPE_PP(tmp) != IS_NULL;
00587                                    case 2:
00588                                           return 1;
00589                                    default:
00590                                           return zend_is_true(*tmp);
00591                             }
00592                      }
00593                      return 0;
00594               } else {
00595                      return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
00596               }
00597        case IS_DOUBLE:
00598        case IS_RESOURCE:
00599        case IS_BOOL: 
00600        case IS_LONG: 
00601               if (offset->type == IS_DOUBLE) {
00602                      index = (long)Z_DVAL_P(offset);
00603               } else {
00604                      index = Z_LVAL_P(offset);
00605               }
00606               if (check_empty) {
00607                      HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00608                      if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
00609                             switch (check_empty) {
00610                                    case 0:
00611                                           return Z_TYPE_PP(tmp) != IS_NULL;
00612                                    case 2:
00613                                           return 1;
00614                                    default:
00615                                           return zend_is_true(*tmp);
00616                             }
00617                      }
00618                      return 0;
00619               } else {
00620                      return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
00621               }
00622        default:
00623               zend_error(E_WARNING, "Illegal offset type");
00624        }
00625        return 0;
00626 } /* }}} */
00627 
00628 static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
00629 {
00630        return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
00631 } /* }}} */
00632 
00633 /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
00634        proto bool ArrayIterator::offsetExists(mixed $index)
00635    Returns whether the requested $index exists. */
00636 SPL_METHOD(Array, offsetExists)
00637 {
00638        zval *index;
00639        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
00640               return;
00641        }
00642        RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
00643 } /* }}} */
00644 
00645 /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
00646        proto mixed ArrayIterator::offsetGet(mixed $index)
00647    Returns the value at the specified $index. */
00648 SPL_METHOD(Array, offsetGet)
00649 {
00650        zval *index, *value;
00651        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
00652               return;
00653        }
00654        value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
00655        RETURN_ZVAL(value, 1, 0);
00656 } /* }}} */
00657 
00658 /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
00659        proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
00660    Sets the value at the specified $index to $newval. */
00661 SPL_METHOD(Array, offsetSet)
00662 {
00663        zval *index, *value;
00664        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
00665               return;
00666        }
00667        spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
00668 } /* }}} */
00669 
00670 
00671 void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
00672 {
00673        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00674        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00675 
00676        if (!aht) {
00677               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
00678               return;
00679        }
00680        
00681        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
00682               php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
00683               return;
00684        }
00685 
00686        spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
00687        if (!intern->pos) {
00688               spl_array_set_pos(intern, aht->pListTail);
00689        }
00690 } /* }}} */
00691 
00692 /* {{{ proto void ArrayObject::append(mixed $newval)
00693        proto void ArrayIterator::append(mixed $newval)
00694    Appends the value (cannot be called for objects). */
00695 SPL_METHOD(Array, append)
00696 {
00697        zval *value;
00698 
00699        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
00700               return;
00701        }
00702        spl_array_iterator_append(getThis(), value TSRMLS_CC);
00703 } /* }}} */
00704 
00705 /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
00706        proto void ArrayIterator::offsetUnset(mixed $index)
00707    Unsets the value at the specified $index. */
00708 SPL_METHOD(Array, offsetUnset)
00709 {
00710        zval *index;
00711        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
00712               return;
00713        }
00714        spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
00715 } /* }}} */
00716 
00717 /* {{{ proto array ArrayObject::getArrayCopy()
00718       proto array ArrayIterator::getArrayCopy()
00719    Return a copy of the contained array */
00720 SPL_METHOD(Array, getArrayCopy)
00721 {
00722        zval *object = getThis(), *tmp;
00723        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00724     
00725     array_init(return_value);
00726        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*));
00727 } /* }}} */
00728 
00729 static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
00730 {
00731        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00732        HashTable *result;
00733 
00734        if (intern->nApplyCount > 1) {
00735               php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
00736        }
00737 
00738        intern->nApplyCount++;
00739        result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
00740        intern->nApplyCount--;
00741        return result;
00742 } /* }}} */
00743 
00744 static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
00745 {
00746        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
00747        zval *tmp, *storage;
00748        int name_len;
00749        char *zname;
00750        zend_class_entry *base;
00751 
00752        *is_temp = 0;
00753 
00754        if (HASH_OF(intern->array) == intern->std.properties) {
00755               return intern->std.properties;
00756        } else {
00757               if (intern->debug_info == NULL) {
00758                      ALLOC_HASHTABLE(intern->debug_info);
00759                      ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
00760               }
00761 
00762               if (intern->debug_info->nApplyCount == 0) {
00763                      zend_hash_clean(intern->debug_info);
00764                      zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00765 
00766                      storage = intern->array;
00767                      zval_add_ref(&storage);
00768 
00769                      base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
00770                      zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
00771                      zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
00772                      efree(zname);
00773               }
00774 
00775               return intern->debug_info;
00776        }
00777 }
00778 /* }}} */
00779 
00780 static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
00781 {
00782        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00783 
00784        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
00785        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
00786               return spl_array_read_dimension(object, member, type TSRMLS_CC);
00787        }
00788        return std_object_handlers.read_property(object, member, type TSRMLS_CC);
00789 } /* }}} */
00790 
00791 static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
00792 {
00793        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00794 
00795        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
00796        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
00797               spl_array_write_dimension(object, member, value TSRMLS_CC);
00798               return;
00799        }
00800        std_object_handlers.write_property(object, member, value TSRMLS_CC);
00801 } /* }}} */
00802 
00803 static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
00804 {
00805        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00806 
00807        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
00808        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
00809               return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC);
00810        }
00811        return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
00812 } /* }}} */
00813 
00814 static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
00815 {
00816        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00817 
00818        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
00819        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
00820               return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
00821        }
00822        return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
00823 
00824 } /* }}} */
00825 
00826 static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
00827 {
00828        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
00829 
00830        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
00831        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
00832               spl_array_unset_dimension(object, member TSRMLS_CC);
00833               spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
00834               return;
00835        }
00836        std_object_handlers.unset_property(object, member TSRMLS_CC);
00837 } /* }}} */
00838 
00839 static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
00840 {
00841        char *string_key;
00842        uint string_length;
00843        ulong num_key;
00844 
00845        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
00846               do {
00847                      if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
00848                             if (!string_length || string_key[0]) {
00849                                    return SUCCESS;
00850                             }
00851                      } else {
00852                             return SUCCESS;
00853                      }
00854                      if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
00855                             return FAILURE;
00856                      }
00857                      zend_hash_move_forward_ex(aht, &intern->pos);
00858                      spl_array_update_pos(intern);
00859               } while (1);
00860        }
00861        return FAILURE;
00862 } /* }}} */
00863 
00864 static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
00865 {
00866        zend_hash_move_forward_ex(aht, &intern->pos);
00867        spl_array_update_pos(intern);
00868        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
00869               return spl_array_skip_protected(intern, aht TSRMLS_CC);
00870        } else {
00871               return zend_hash_has_more_elements_ex(aht, &intern->pos);
00872        }
00873 } /* }}} */
00874 
00875 static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
00876 {
00877        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
00878               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
00879               return FAILURE;
00880        }
00881 
00882        return spl_array_next_no_verify(intern, aht TSRMLS_CC);
00883 } /* }}} */
00884 
00885 static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
00886 {
00887        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
00888 
00889        return spl_array_next_ex(intern, aht TSRMLS_CC);
00890 
00891 } /* }}} */
00892 
00893 /* define an overloaded iterator structure */
00894 typedef struct {
00895        zend_user_iterator    intern;
00896        spl_array_object      *object;
00897 } spl_array_it;
00898 
00899 static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
00900 {
00901        spl_array_it *iterator = (spl_array_it *)iter;
00902 
00903        zend_user_it_invalidate_current(iter TSRMLS_CC);
00904        zval_ptr_dtor((zval**)&iterator->intern.it.data);
00905 
00906        efree(iterator);
00907 }
00908 /* }}} */
00909        
00910 static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
00911 {
00912        spl_array_it       *iterator = (spl_array_it *)iter;
00913        spl_array_object   *object   = iterator->object;
00914        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
00915 
00916        if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
00917               return zend_user_it_valid(iter TSRMLS_CC);
00918        } else {
00919               if (!aht) {
00920                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
00921                      return FAILURE;
00922               }
00923        
00924               if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
00925                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
00926                      return FAILURE;
00927               } else {
00928                      return zend_hash_has_more_elements_ex(aht, &object->pos);
00929               }
00930        }
00931 }
00932 /* }}} */
00933 
00934 static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
00935 {
00936        spl_array_it       *iterator = (spl_array_it *)iter;
00937        spl_array_object   *object   = iterator->object;
00938        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
00939 
00940        if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
00941               zend_user_it_get_current_data(iter, data TSRMLS_CC);
00942        } else {
00943               if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
00944                      *data = NULL;
00945               }
00946        }
00947 }
00948 /* }}} */
00949 
00950 static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
00951 {
00952        spl_array_it       *iterator = (spl_array_it *)iter;
00953        spl_array_object   *object   = iterator->object;
00954        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
00955 
00956        if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
00957               return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
00958        } else {
00959               if (!aht) {
00960                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
00961                      return HASH_KEY_NON_EXISTANT;
00962               }
00963        
00964               if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
00965                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
00966                      return HASH_KEY_NON_EXISTANT;
00967               }
00968        
00969               return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
00970        }
00971 }
00972 /* }}} */
00973 
00974 static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
00975 {
00976        spl_array_it       *iterator = (spl_array_it *)iter;
00977        spl_array_object   *object   = iterator->object;
00978        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
00979 
00980        if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
00981               zend_user_it_move_forward(iter TSRMLS_CC);
00982        } else {
00983               zend_user_it_invalidate_current(iter TSRMLS_CC);
00984               if (!aht) {
00985                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
00986                      return;
00987               }
00988        
00989               if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
00990                      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
00991               } else {
00992                      spl_array_next_no_verify(object, aht TSRMLS_CC);
00993               }
00994        }
00995 }
00996 /* }}} */
00997 
00998 static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
00999 {
01000 
01001        zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
01002        spl_array_update_pos(intern);
01003        spl_array_skip_protected(intern, aht TSRMLS_CC);
01004 
01005 } /* }}} */
01006 
01007 static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
01008 {
01009        HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01010 
01011        if (!aht) {
01012               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
01013               return;
01014        }
01015 
01016        spl_array_rewind_ex(intern, aht TSRMLS_CC);
01017 }
01018 /* }}} */
01019 
01020 static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
01021 {
01022        spl_array_it       *iterator = (spl_array_it *)iter;
01023        spl_array_object   *object   = iterator->object;
01024 
01025        if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
01026               zend_user_it_rewind(iter TSRMLS_CC);
01027        } else {
01028               zend_user_it_invalidate_current(iter TSRMLS_CC);
01029               spl_array_rewind(object TSRMLS_CC);
01030        }
01031 }
01032 /* }}} */
01033 
01034 /* {{{ spl_array_set_array */
01035 static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
01036 
01037        if (Z_TYPE_PP(array) == IS_ARRAY) {
01038               SEPARATE_ZVAL_IF_NOT_REF(array);
01039        }
01040 
01041        if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
01042               zval_ptr_dtor(&intern->array);
01043               if (just_array)      {
01044                      spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
01045                      ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
01046               }             
01047               ar_flags |= SPL_ARRAY_USE_OTHER;
01048               intern->array = *array;
01049        } else {
01050               if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
01051                      zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
01052                      return;
01053               }
01054               zval_ptr_dtor(&intern->array);
01055               intern->array = *array;
01056        }
01057        if (object == *array) {
01058               intern->ar_flags |= SPL_ARRAY_IS_SELF;
01059               intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
01060        } else {
01061               intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
01062        }
01063        intern->ar_flags |= ar_flags;
01064        Z_ADDREF_P(intern->array);
01065        if (Z_TYPE_PP(array) == IS_OBJECT) {
01066               zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
01067               if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
01068               || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
01069                      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);
01070               }
01071        }
01072 
01073        spl_array_rewind(intern TSRMLS_CC);
01074 }
01075 /* }}} */
01076 
01077 /* iterator handler table */
01078 zend_object_iterator_funcs spl_array_it_funcs = {
01079        spl_array_it_dtor,
01080        spl_array_it_valid,
01081        spl_array_it_get_current_data,
01082        spl_array_it_get_current_key,
01083        spl_array_it_move_forward,
01084        spl_array_it_rewind
01085 };
01086 
01087 zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
01088 {
01089        spl_array_it       *iterator;
01090        spl_array_object   *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01091 
01092        if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
01093               zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
01094        }
01095 
01096        iterator     = emalloc(sizeof(spl_array_it));
01097 
01098        Z_ADDREF_P(object);
01099        iterator->intern.it.data = (void*)object;
01100        iterator->intern.it.funcs = &spl_array_it_funcs;
01101        iterator->intern.ce = ce;
01102        iterator->intern.value = NULL;
01103        iterator->object = array_object;
01104        
01105        return (zend_object_iterator*)iterator;
01106 }
01107 /* }}} */
01108 
01109 /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
01110        proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
01111    Constructs a new array iterator from a path. */
01112 SPL_METHOD(Array, __construct)
01113 {
01114        zval *object = getThis();
01115        spl_array_object *intern;
01116        zval **array;
01117        long ar_flags = 0;
01118        zend_class_entry *ce_get_iterator = spl_ce_Iterator;
01119        zend_error_handling error_handling;
01120 
01121        if (ZEND_NUM_ARGS() == 0) {
01122               return; /* nothing to do */
01123        }
01124 
01125        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
01126 
01127        intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01128 
01129        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
01130               zend_restore_error_handling(&error_handling TSRMLS_CC);
01131               return;
01132        }
01133 
01134        if (ZEND_NUM_ARGS() > 2) {
01135               intern->ce_get_iterator = ce_get_iterator;
01136        }
01137 
01138        ar_flags &= ~SPL_ARRAY_INT_MASK;
01139 
01140        spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
01141 
01142        zend_restore_error_handling(&error_handling TSRMLS_CC);
01143 
01144 }
01145  /* }}} */
01146 
01147 /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
01148    Set the class used in getIterator. */
01149 SPL_METHOD(Array, setIteratorClass)
01150 {
01151        zval *object = getThis();
01152        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01153        zend_class_entry * ce_get_iterator = spl_ce_Iterator;
01154 
01155        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
01156               return;
01157        }
01158 
01159        intern->ce_get_iterator = ce_get_iterator;
01160 }
01161 /* }}} */
01162 
01163 /* {{{ proto string ArrayObject::getIteratorClass()
01164    Get the class used in getIterator. */
01165 SPL_METHOD(Array, getIteratorClass)
01166 {
01167        zval *object = getThis();
01168        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01169        
01170        if (zend_parse_parameters_none() == FAILURE) {
01171               return;
01172        }
01173 
01174        RETURN_STRING(intern->ce_get_iterator->name, 1);
01175 }
01176 /* }}} */
01177 
01178 /* {{{ proto int ArrayObject::getFlags()
01179    Get flags */
01180 SPL_METHOD(Array, getFlags)
01181 {
01182        zval *object = getThis();
01183        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01184        
01185        if (zend_parse_parameters_none() == FAILURE) {
01186               return;
01187        }
01188        
01189        RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
01190 }
01191 /* }}} */
01192 
01193 /* {{{ proto void ArrayObject::setFlags(int flags)
01194    Set flags */
01195 SPL_METHOD(Array, setFlags)
01196 {
01197        zval *object = getThis();
01198        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01199        long ar_flags = 0;
01200 
01201        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
01202               return;
01203        }
01204        
01205        intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
01206 }
01207 /* }}} */
01208 
01209 /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
01210    Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
01211 SPL_METHOD(Array, exchangeArray)
01212 {
01213        zval *object = getThis(), *tmp, **array;
01214        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01215 
01216        array_init(return_value);
01217        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*));
01218        
01219        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
01220               return;
01221        }
01222 
01223        spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
01224 
01225 }
01226 /* }}} */
01227 
01228 /* {{{ proto ArrayIterator ArrayObject::getIterator()
01229    Create a new iterator from a ArrayObject instance */
01230 SPL_METHOD(Array, getIterator)
01231 {
01232        zval *object = getThis();
01233        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01234        spl_array_object *iterator;
01235        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01236        
01237        if (zend_parse_parameters_none() == FAILURE) {
01238               return;
01239        }
01240 
01241        if (!aht) {
01242               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01243               return;
01244        }
01245 
01246        return_value->type = IS_OBJECT;
01247        return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
01248        Z_SET_REFCOUNT_P(return_value, 1);
01249        Z_SET_ISREF_P(return_value);
01250 }
01251 /* }}} */
01252 
01253 /* {{{ proto void ArrayIterator::rewind()
01254    Rewind array back to the start */
01255 SPL_METHOD(Array, rewind)
01256 {
01257        zval *object = getThis();
01258        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01259        
01260        if (zend_parse_parameters_none() == FAILURE) {
01261               return;
01262        }
01263 
01264        spl_array_rewind(intern TSRMLS_CC);
01265 }
01266 /* }}} */
01267 
01268 /* {{{ proto void ArrayIterator::seek(int $position)
01269    Seek to position. */
01270 SPL_METHOD(Array, seek)
01271 {
01272        long opos, position;
01273        zval *object = getThis();
01274        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01275        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01276        int result;
01277 
01278        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
01279               return;
01280        }
01281 
01282        if (!aht) {
01283               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01284               return;
01285        }
01286 
01287        opos = position;
01288 
01289        if (position >= 0) { /* negative values are not supported */
01290               spl_array_rewind(intern TSRMLS_CC);
01291               result = SUCCESS;
01292               
01293               while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
01294        
01295               if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
01296                      return; /* ok */
01297               }
01298        }
01299        zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
01300 } /* }}} */
01301 
01302 int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
01303 {
01304        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01305        HashPosition pos;
01306 
01307        if (!aht) {
01308               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01309               *count = 0;
01310               return FAILURE;
01311        }
01312 
01313        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
01314               /* We need to store the 'pos' since we'll modify it in the functions 
01315                * we're going to call and which do not support 'pos' as parameter. */
01316               pos = intern->pos;
01317               *count = 0;
01318               spl_array_rewind(intern TSRMLS_CC);
01319               while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
01320                      (*count)++;
01321               }
01322               spl_array_set_pos(intern, pos);
01323               return SUCCESS;
01324        } else {
01325               *count = zend_hash_num_elements(aht);
01326               return SUCCESS;
01327        }
01328 } /* }}} */
01329 
01330 int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
01331 {
01332        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01333 
01334        if (intern->fptr_count) {
01335               zval *rv;
01336               zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
01337               if (rv) {
01338                      zval_ptr_dtor(&intern->retval);
01339                      MAKE_STD_ZVAL(intern->retval);
01340                      ZVAL_ZVAL(intern->retval, rv, 1, 1);
01341                      convert_to_long(intern->retval);
01342                      *count = (long) Z_LVAL_P(intern->retval);
01343                      return SUCCESS;
01344               }
01345               *count = 0;
01346               return FAILURE;
01347        }
01348        return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
01349 } /* }}} */
01350 
01351 /* {{{ proto int ArrayObject::count()
01352        proto int ArrayIterator::count()
01353    Return the number of elements in the Iterator. */
01354 SPL_METHOD(Array, count)
01355 {
01356        long count;
01357        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01358        
01359        if (zend_parse_parameters_none() == FAILURE) {
01360               return;
01361        }
01362 
01363        spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
01364 
01365        RETURN_LONG(count);
01366 } /* }}} */
01367 
01368 static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
01369 {
01370        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01371        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01372        zval *tmp, *arg;
01373        zval *retval_ptr = NULL;
01374        
01375        MAKE_STD_ZVAL(tmp);
01376        Z_TYPE_P(tmp) = IS_ARRAY;
01377        Z_ARRVAL_P(tmp) = aht;
01378        
01379        if (use_arg) {
01380               if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
01381                      Z_TYPE_P(tmp) = IS_NULL;
01382                      zval_ptr_dtor(&tmp);
01383                      zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
01384                      return;
01385               }
01386               aht->nApplyCount++;
01387               zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
01388               aht->nApplyCount--;
01389        } else {
01390               aht->nApplyCount++;
01391               zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
01392               aht->nApplyCount--;
01393        }
01394        Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
01395        zval_ptr_dtor(&tmp);
01396        if (retval_ptr) {
01397               COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
01398        }
01399 } /* }}} */
01400 
01401 #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
01402 SPL_METHOD(cname, fname) \
01403 { \
01404        spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
01405 }
01406 
01407 /* {{{ proto int ArrayObject::asort()
01408        proto int ArrayIterator::asort()
01409    Sort the entries by values. */
01410 SPL_ARRAY_METHOD(Array, asort, 0) /* }}} */
01411 
01412 /* {{{ proto int ArrayObject::ksort()
01413        proto int ArrayIterator::ksort()
01414    Sort the entries by key. */
01415 SPL_ARRAY_METHOD(Array, ksort, 0) /* }}} */
01416 
01417 /* {{{ proto int ArrayObject::uasort(callback cmp_function)
01418        proto int ArrayIterator::uasort(callback cmp_function)
01419    Sort the entries by values user defined function. */
01420 SPL_ARRAY_METHOD(Array, uasort, 1) /* }}} */
01421 
01422 /* {{{ proto int ArrayObject::uksort(callback cmp_function)
01423        proto int ArrayIterator::uksort(callback cmp_function)
01424    Sort the entries by key using user defined function. */
01425 SPL_ARRAY_METHOD(Array, uksort, 1) /* }}} */
01426 
01427 /* {{{ proto int ArrayObject::natsort()
01428        proto int ArrayIterator::natsort()
01429    Sort the entries by values using "natural order" algorithm. */
01430 SPL_ARRAY_METHOD(Array, natsort, 0) /* }}} */
01431 
01432 /* {{{ proto int ArrayObject::natcasesort()
01433        proto int ArrayIterator::natcasesort()
01434    Sort the entries by key using case insensitive "natural order" algorithm. */
01435 SPL_ARRAY_METHOD(Array, natcasesort, 0) /* }}} */
01436 
01437 /* {{{ proto mixed|NULL ArrayIterator::current()
01438    Return current array entry */
01439 SPL_METHOD(Array, current)
01440 {
01441        zval *object = getThis();
01442        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01443        zval **entry;
01444        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01445        
01446        if (zend_parse_parameters_none() == FAILURE) {
01447               return;
01448        }
01449 
01450        if (!aht) {
01451               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01452               return;
01453        }
01454 
01455        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
01456               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
01457               return;
01458        }
01459 
01460        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
01461               return;
01462        }
01463        RETVAL_ZVAL(*entry, 1, 0);
01464 }
01465 /* }}} */
01466 
01467 /* {{{ proto mixed|NULL ArrayIterator::key()
01468    Return current array key */
01469 SPL_METHOD(Array, key)
01470 {
01471        if (zend_parse_parameters_none() == FAILURE) {
01472               return;
01473        }
01474        
01475        spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
01476 } /* }}} */
01477 
01478 void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
01479 {
01480        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01481        char *string_key;
01482        uint string_length;
01483        ulong num_key;
01484        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01485 
01486        if (!aht) {
01487               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01488               return;
01489        }
01490 
01491        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
01492               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
01493               return;
01494        }
01495 
01496        switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
01497               case HASH_KEY_IS_STRING:
01498                      RETVAL_STRINGL(string_key, string_length - 1, 0);
01499                      break;
01500               case HASH_KEY_IS_LONG:
01501                      RETVAL_LONG(num_key);
01502                      break;
01503               case HASH_KEY_NON_EXISTANT:
01504                      return;
01505        }
01506 }
01507 /* }}} */
01508 
01509 /* {{{ proto void ArrayIterator::next()
01510    Move to next entry */
01511 SPL_METHOD(Array, next)
01512 {
01513        zval *object = getThis();
01514        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01515        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01516 
01517        if (zend_parse_parameters_none() == FAILURE) {
01518               return;
01519        }
01520        
01521        if (!aht) {
01522               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01523               return;
01524        }
01525 
01526        spl_array_next_ex(intern, aht TSRMLS_CC);
01527 }
01528 /* }}} */ 
01529 
01530 /* {{{ proto bool ArrayIterator::valid()
01531    Check whether array contains more entries */
01532 SPL_METHOD(Array, valid)
01533 {
01534        zval *object = getThis();
01535        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01536        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01537 
01538        if (zend_parse_parameters_none() == FAILURE) {
01539               return;
01540        }
01541        
01542        if (!aht) {
01543               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01544               return;
01545        }
01546 
01547        if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
01548               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
01549               RETURN_FALSE;
01550        } else {
01551               RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
01552        }
01553 }
01554 /* }}} */
01555 
01556 /* {{{ proto bool RecursiveArrayIterator::hasChildren()
01557    Check whether current element has children (e.g. is an array) */
01558 SPL_METHOD(Array, hasChildren)
01559 {
01560        zval *object = getThis(), **entry;
01561        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01562        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01563        
01564        if (zend_parse_parameters_none() == FAILURE) {
01565               return;
01566        }
01567        
01568        if (!aht) {
01569               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01570               RETURN_FALSE;
01571        }
01572 
01573        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
01574               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
01575               RETURN_FALSE;
01576        }
01577 
01578        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
01579               RETURN_FALSE;
01580        }
01581 
01582        RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
01583 }
01584 /* }}} */
01585 
01586 /* {{{ proto object RecursiveArrayIterator::getChildren()
01587    Create a sub iterator for the current element (same class as $this) */
01588 SPL_METHOD(Array, getChildren)
01589 {
01590        zval *object = getThis(), **entry, *flags;
01591        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01592        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01593        
01594        if (zend_parse_parameters_none() == FAILURE) {
01595               return;
01596        }
01597 
01598        if (!aht) {
01599               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01600               return;
01601        }
01602 
01603        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
01604               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
01605               return;
01606        }
01607 
01608        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
01609               return;
01610        }
01611 
01612        if (Z_TYPE_PP(entry) == IS_OBJECT) {
01613               if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
01614                      return;
01615               }
01616               if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
01617                      RETURN_ZVAL(*entry, 0, 0);
01618               }
01619        }
01620 
01621        MAKE_STD_ZVAL(flags);
01622        ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
01623        spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
01624        zval_ptr_dtor(&flags);
01625 }
01626 /* }}} */
01627 
01628 smart_str spl_array_serialize_helper(spl_array_object *intern, php_serialize_data_t *var_hash_p TSRMLS_DC) { /* {{{ */
01629        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
01630        zval members, *pmembers;
01631        smart_str buf = {0};
01632        zval *flags;
01633        
01634        if (!aht) {
01635               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
01636               return buf;
01637        }
01638 
01639        MAKE_STD_ZVAL(flags);
01640        ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
01641 
01642        /* storage */
01643        smart_str_appendl(&buf, "x:", 2);
01644        php_var_serialize(&buf, &flags, var_hash_p TSRMLS_CC);
01645        zval_ptr_dtor(&flags);
01646 
01647        if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
01648               php_var_serialize(&buf, &intern->array, var_hash_p TSRMLS_CC);
01649               smart_str_appendc(&buf, ';');
01650        }
01651 
01652        /* members */
01653        smart_str_appendl(&buf, "m:", 2);
01654        INIT_PZVAL(&members);
01655        Z_ARRVAL(members) = intern->std.properties;
01656        Z_TYPE(members) = IS_ARRAY;
01657        pmembers = &members;
01658        php_var_serialize(&buf, &pmembers, var_hash_p TSRMLS_CC); /* finishes the string */
01659 
01660        /* done */
01661        return buf;
01662 }
01663 /* }}} */
01664 
01665 /* {{{ proto string ArrayObject::serialize()
01666    Serialize the object */
01667 SPL_METHOD(Array, serialize)
01668 {
01669        zval *object = getThis();
01670        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01671        int was_in_serialize = intern->serialize_data != NULL;
01672        smart_str buf;
01673        
01674        if (zend_parse_parameters_none() == FAILURE) {
01675               return;
01676        }
01677 
01678        if (!was_in_serialize) {
01679               intern->serialize_data = emalloc(sizeof(php_serialize_data_t));
01680               PHP_VAR_SERIALIZE_INIT(*intern->serialize_data);
01681        }
01682 
01683        buf = spl_array_serialize_helper(intern, intern->serialize_data TSRMLS_CC);
01684 
01685        if (!was_in_serialize) {
01686               PHP_VAR_SERIALIZE_DESTROY(*intern->serialize_data);
01687               efree(intern->serialize_data);
01688               intern->serialize_data = NULL;
01689        }
01690 
01691        if (buf.c) {
01692               RETURN_STRINGL(buf.c, buf.len, 0);
01693        }
01694 
01695        RETURN_NULL();
01696 } /* }}} */
01697 
01698 int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
01699 {
01700        spl_array_object     *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
01701 
01702        if (intern->fptr_serialize) {
01703               int retval;
01704               php_serialize_data_t *before;
01705 
01706               before = intern->serialize_data;
01707               intern->serialize_data = (php_serialize_data_t *)data;
01708 
01709               retval = zend_user_serialize(object, buffer, buf_len, data TSRMLS_CC);
01710 
01711               intern->serialize_data = before;
01712 
01713               return retval;
01714        } else {
01715               smart_str buf;
01716 
01717               buf = spl_array_serialize_helper(intern, (php_serialize_data_t *)data TSRMLS_CC);
01718 
01719               if (buf.c) {
01720                      *buffer  = (unsigned char*)estrndup(buf.c, buf.len);
01721                      *buf_len = buf.len;
01722                      efree(buf.c);
01723                      return SUCCESS;
01724               } else {
01725                      return FAILURE;
01726               }
01727        }
01728 }
01729 /* }}} */
01730 
01731 void spl_array_unserialize_helper(spl_array_object *intern, const unsigned char *buf, int buf_len, php_unserialize_data_t *var_hash_p TSRMLS_DC) /* {{{ */
01732 {
01733        const unsigned char *p, *s;
01734        zval *pmembers, *pflags = NULL;
01735        long flags;
01736 
01737        /* storage */
01738        s = p = buf;
01739 
01740        if (*p!= 'x' || *++p != ':') {
01741               goto outexcept;
01742        }
01743        ++p;
01744 
01745        ALLOC_INIT_ZVAL(pflags);
01746        if (!php_var_unserialize(&pflags, &p, s + buf_len, var_hash_p TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
01747               zval_ptr_dtor(&pflags);
01748               goto outexcept;
01749        }
01750 
01751        --p; /* for ';' */
01752        flags = Z_LVAL_P(pflags);
01753        zval_ptr_dtor(&pflags);
01754        /* flags needs to be verified and we also need to verify whether the next
01755         * thing we get is ';'. After that we require an 'm' or somethign else
01756         * where 'm' stands for members and anything else should be an array. If
01757         * neither 'a' or 'm' follows we have an error. */
01758 
01759        if (*p != ';') {
01760               goto outexcept;
01761        }
01762        ++p;
01763 
01764        if (*p!='m') {
01765               if (*p!='a' && *p!='O' && *p!='C') {
01766                      goto outexcept;
01767               }
01768               intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
01769               intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
01770               zval_ptr_dtor(&intern->array);
01771               ALLOC_INIT_ZVAL(intern->array);
01772               if (!php_var_unserialize(&intern->array, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
01773                      goto outexcept;
01774               }
01775        }
01776        if (*p != ';') {
01777               goto outexcept;
01778        }
01779        ++p;
01780 
01781        /* members */
01782        if (*p!= 'm' || *++p != ':') {
01783               goto outexcept;
01784        }
01785        ++p;
01786 
01787        ALLOC_INIT_ZVAL(pmembers);
01788        if (!php_var_unserialize(&pmembers, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
01789               zval_ptr_dtor(&pmembers);
01790               goto outexcept;
01791        }
01792 
01793        /* copy members */
01794        zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
01795        zval_ptr_dtor(&pmembers);
01796 
01797        /* done reading $serialized */
01798        return;
01799 
01800 outexcept:
01801        zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - (char *)buf), buf_len);
01802        return;
01803 
01804 }
01805 /* }}} */
01806 
01807 /* {{{ proto void ArrayObject::unserialize(string serialized)
01808    Unserialize the object */
01809 SPL_METHOD(Array, unserialize)
01810 {
01811        char *buf;
01812        int buf_len;
01813        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
01814        int was_in_unserialize = intern->unserialize_data != NULL;
01815 
01816        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
01817               return;
01818        }
01819 
01820        if (buf_len == 0) {
01821               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
01822               return;
01823        }
01824 
01825        if (!was_in_unserialize) {
01826               intern->unserialize_data = emalloc(sizeof(php_unserialize_data_t));
01827               PHP_VAR_UNSERIALIZE_INIT(*intern->unserialize_data);
01828        }
01829 
01830        spl_array_unserialize_helper(intern, (const unsigned char *)buf, buf_len, intern->unserialize_data TSRMLS_CC);
01831 
01832        if (!was_in_unserialize) {
01833               PHP_VAR_UNSERIALIZE_DESTROY(*intern->unserialize_data);
01834               efree(intern->unserialize_data);
01835               intern->unserialize_data = NULL;
01836        }
01837 } /* }}} */
01838 
01839 int spl_array_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)
01840 {
01841        spl_array_object *intern;
01842 
01843        object_init_ex(*object, ce);
01844        intern = (spl_array_object*)zend_object_store_get_object(*object TSRMLS_CC);
01845 
01846        if (intern->fptr_unserialize) {
01847               zval *zdata;
01848               php_unserialize_data_t *before;
01849               MAKE_STD_ZVAL(zdata);
01850               ZVAL_STRINGL(zdata, (char *)buf, buf_len, 1);
01851 
01852               before = intern->unserialize_data;
01853               intern->unserialize_data = (php_unserialize_data_t *)data;
01854 
01855               zend_call_method_with_1_params(object, ce, &ce->unserialize_func, "unserialize", NULL, zdata);
01856 
01857               intern->unserialize_data = before;
01858 
01859               zval_ptr_dtor(&zdata);
01860        } else {
01861               spl_array_unserialize_helper(intern, buf, buf_len, (php_unserialize_data_t *)data TSRMLS_CC);
01862        }
01863 
01864        if (EG(exception)) {
01865               return FAILURE;
01866        } else {
01867               return SUCCESS;
01868        }
01869 } 
01870 /* }}} */
01871 
01872 /* {{{ arginfo and function tbale */
01873 ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
01874        ZEND_ARG_INFO(0, array)
01875 ZEND_END_ARG_INFO()
01876 
01877 ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
01878        ZEND_ARG_INFO(0, index)
01879 ZEND_END_ARG_INFO()
01880 
01881 ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
01882        ZEND_ARG_INFO(0, index)
01883        ZEND_ARG_INFO(0, newval)
01884 ZEND_END_ARG_INFO()
01885 
01886 ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
01887        ZEND_ARG_INFO(0, value)
01888 ZEND_END_ARG_INFO()
01889 
01890 ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
01891        ZEND_ARG_INFO(0, position)
01892 ZEND_END_ARG_INFO()
01893 
01894 ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
01895        ZEND_ARG_INFO(0, array)
01896 ZEND_END_ARG_INFO()
01897 
01898 ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
01899        ZEND_ARG_INFO(0, flags)
01900 ZEND_END_ARG_INFO()
01901 
01902 ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
01903        ZEND_ARG_INFO(0, iteratorClass)
01904 ZEND_END_ARG_INFO()
01905 
01906 ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
01907        ZEND_ARG_INFO(0, cmp_function)
01908 ZEND_END_ARG_INFO();
01909 
01910 ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
01911        ZEND_ARG_INFO(0, serialized)
01912 ZEND_END_ARG_INFO();
01913 
01914 ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
01915 ZEND_END_ARG_INFO()
01916 
01917 static const zend_function_entry spl_funcs_ArrayObject[] = {
01918        SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
01919        SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01920        SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01921        SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
01922        SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01923        SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
01924        SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
01925        SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01926        SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
01927        SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
01928        SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01929        SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01930        SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
01931        SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
01932        SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
01933        SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
01934        SPL_ME(Array, unserialize,      arginfo_array_unserialize,      ZEND_ACC_PUBLIC)
01935        SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
01936        /* ArrayObject specific */
01937        SPL_ME(Array, getIterator,      arginfo_array_void,             ZEND_ACC_PUBLIC)
01938        SPL_ME(Array, exchangeArray,    arginfo_array_exchangeArray,    ZEND_ACC_PUBLIC)
01939        SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
01940        SPL_ME(Array, getIteratorClass, arginfo_array_void,             ZEND_ACC_PUBLIC)
01941        PHP_FE_END
01942 };
01943 
01944 static const zend_function_entry spl_funcs_ArrayIterator[] = {
01945        SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
01946        SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01947        SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01948        SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
01949        SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
01950        SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
01951        SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
01952        SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01953        SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
01954        SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
01955        SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01956        SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01957        SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
01958        SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
01959        SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
01960        SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
01961        SPL_ME(Array, unserialize,      arginfo_array_unserialize,      ZEND_ACC_PUBLIC)
01962        SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
01963        /* ArrayIterator specific */
01964        SPL_ME(Array, rewind,           arginfo_array_void,             ZEND_ACC_PUBLIC)
01965        SPL_ME(Array, current,          arginfo_array_void,             ZEND_ACC_PUBLIC)
01966        SPL_ME(Array, key,              arginfo_array_void,             ZEND_ACC_PUBLIC)
01967        SPL_ME(Array, next,             arginfo_array_void,             ZEND_ACC_PUBLIC)
01968        SPL_ME(Array, valid,            arginfo_array_void,             ZEND_ACC_PUBLIC)
01969        SPL_ME(Array, seek,             arginfo_array_seek,             ZEND_ACC_PUBLIC)
01970        PHP_FE_END
01971 };
01972 
01973 static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
01974        SPL_ME(Array, hasChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
01975        SPL_ME(Array, getChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
01976        PHP_FE_END
01977 };
01978 /* }}} */
01979 
01980 /* {{{ PHP_MINIT_FUNCTION(spl_array) */
01981 PHP_MINIT_FUNCTION(spl_array)
01982 {
01983        REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
01984        REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
01985        REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
01986        REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
01987        spl_ce_ArrayObject->serialize   = spl_array_serialize;
01988        spl_ce_ArrayObject->unserialize = spl_array_unserialize;
01989        memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
01990 
01991        spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
01992        spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
01993        spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
01994        spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
01995        spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
01996        spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
01997 
01998        spl_handler_ArrayObject.get_properties = spl_array_get_properties;
01999        spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
02000        spl_handler_ArrayObject.read_property = spl_array_read_property;
02001        spl_handler_ArrayObject.write_property = spl_array_write_property;
02002        spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
02003        spl_handler_ArrayObject.has_property = spl_array_has_property;
02004        spl_handler_ArrayObject.unset_property = spl_array_unset_property;
02005 
02006        REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
02007        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
02008        REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
02009        REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
02010        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
02011        spl_ce_ArrayIterator->serialize   = spl_array_serialize;
02012        spl_ce_ArrayIterator->unserialize = spl_array_unserialize;
02013        memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
02014        spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
02015        
02016        REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
02017        REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
02018        spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
02019 
02020        REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
02021        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
02022 
02023        REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
02024        REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
02025 
02026        REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
02027        REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
02028 
02029        REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
02030 
02031        return SUCCESS;
02032 }
02033 /* }}} */
02034 
02035 /*
02036  * Local variables:
02037  * tab-width: 4
02038  * c-basic-offset: 4
02039  * End:
02040  * vim600: fdm=marker
02041  * vim: noet sw=4 ts=4
02042  */