Annotation of embedaddon/php/ext/spl/spl_array.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.txt                                  |
                     11:    | If you did not receive a copy of the PHP license and are unable to   |
                     12:    | obtain it through the world-wide-web, please send a note to          |
                     13:    | license@php.net so we can mail you a copy immediately.               |
                     14:    +----------------------------------------------------------------------+
                     15:    | Authors: Marcus Boerger <helly@php.net>                              |
                     16:    +----------------------------------------------------------------------+
                     17:  */
                     18: 
                     19: /* $Id: spl_array.c 321634 2012-01-01 13:15:04Z felipe $ */
                     20: 
                     21: #ifdef HAVE_CONFIG_H
                     22: # include "config.h"
                     23: #endif
                     24: 
                     25: #include "php.h"
                     26: #include "php_ini.h"
                     27: #include "ext/standard/info.h"
                     28: #include "ext/standard/php_var.h"
                     29: #include "ext/standard/php_smart_str.h"
                     30: #include "zend_interfaces.h"
                     31: #include "zend_exceptions.h"
                     32: 
                     33: #include "php_spl.h"
                     34: #include "spl_functions.h"
                     35: #include "spl_engine.h"
                     36: #include "spl_iterators.h"
                     37: #include "spl_array.h"
                     38: #include "spl_exceptions.h"
                     39: 
                     40: zend_object_handlers spl_handler_ArrayObject;
                     41: PHPAPI zend_class_entry  *spl_ce_ArrayObject;
                     42: 
                     43: zend_object_handlers spl_handler_ArrayIterator;
                     44: PHPAPI zend_class_entry  *spl_ce_ArrayIterator;
                     45: PHPAPI zend_class_entry  *spl_ce_RecursiveArrayIterator;
                     46: 
                     47: #define SPL_ARRAY_STD_PROP_LIST      0x00000001
                     48: #define SPL_ARRAY_ARRAY_AS_PROPS     0x00000002
                     49: #define SPL_ARRAY_CHILD_ARRAYS_ONLY  0x00000004
                     50: #define SPL_ARRAY_OVERLOADED_REWIND  0x00010000
                     51: #define SPL_ARRAY_OVERLOADED_VALID   0x00020000
                     52: #define SPL_ARRAY_OVERLOADED_KEY     0x00040000
                     53: #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
                     54: #define SPL_ARRAY_OVERLOADED_NEXT    0x00100000
                     55: #define SPL_ARRAY_IS_REF             0x01000000
                     56: #define SPL_ARRAY_IS_SELF            0x02000000
                     57: #define SPL_ARRAY_USE_OTHER          0x04000000
                     58: #define SPL_ARRAY_INT_MASK           0xFFFF0000
                     59: #define SPL_ARRAY_CLONE_MASK         0x0300FFFF
                     60: 
                     61: typedef struct _spl_array_object {
                     62:        zend_object            std;
                     63:        zval                   *array;
                     64:        zval                   *retval;
                     65:        HashPosition           pos;
                     66:        ulong                  pos_h;
                     67:        int                    ar_flags;
                     68:        int                    is_self;
                     69:        zend_function          *fptr_offset_get;
                     70:        zend_function          *fptr_offset_set;
                     71:        zend_function          *fptr_offset_has;
                     72:        zend_function          *fptr_offset_del;
                     73:        zend_function          *fptr_count;
                     74:        zend_function          *fptr_serialize;
                     75:        zend_function          *fptr_unserialize;
                     76:        zend_class_entry       *ce_get_iterator;
                     77:        php_serialize_data_t   *serialize_data;
                     78:        php_unserialize_data_t *unserialize_data;
                     79:        HashTable              *debug_info;
                     80:        unsigned char              nApplyCount;
                     81: } spl_array_object;
                     82: 
                     83: static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
                     84:        if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
                     85:                return intern->std.properties;
                     86:        } 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) {
                     87:                spl_array_object *other  = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
                     88:                return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
                     89:        } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
                     90:                return intern->std.properties;
                     91:        } else {
                     92:                return HASH_OF(intern->array);
                     93:        }
                     94: } /* }}} */
                     95: 
                     96: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
                     97: 
                     98: static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
                     99: {
                    100:        Bucket *pos = intern->pos;
                    101:        if (pos != NULL) {
                    102:                intern->pos_h = pos->h;
                    103:        }
                    104: } /* }}} */
                    105: 
                    106: static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
                    107: {
                    108:        intern->pos = pos;
                    109:        spl_array_update_pos(intern);
                    110: } /* }}} */
                    111: 
                    112: SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
                    113: {
                    114:        Bucket *p;
                    115: 
                    116: /*     IS_CONSISTENT(ht);*/
                    117: 
                    118: /*     HASH_PROTECT_RECURSION(ht);*/
                    119:        p = ht->arBuckets[intern->pos_h & ht->nTableMask];
                    120:        while (p != NULL) {
                    121:                if (p == intern->pos) {
                    122:                        return SUCCESS;
                    123:                }
                    124:                p = p->pNext;
                    125:        }
                    126: /*     HASH_UNPROTECT_RECURSION(ht); */
                    127:        spl_array_rewind(intern TSRMLS_CC);
                    128:        return FAILURE;
                    129: 
                    130: } /* }}} */
                    131: 
                    132: SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
                    133: {
                    134:        HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    135:        return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
                    136: }
                    137: /* }}} */
                    138: 
                    139: /* {{{ spl_array_object_free_storage */
                    140: static void spl_array_object_free_storage(void *object TSRMLS_DC)
                    141: {
                    142:        spl_array_object *intern = (spl_array_object *)object;
                    143: 
                    144:        zend_object_std_dtor(&intern->std TSRMLS_CC);
                    145: 
                    146:        zval_ptr_dtor(&intern->array);
                    147:        zval_ptr_dtor(&intern->retval);
                    148: 
                    149:        if (intern->debug_info != NULL) {
                    150:                zend_hash_destroy(intern->debug_info);
                    151:                efree(intern->debug_info);
                    152:        }
                    153: 
                    154:        efree(object);
                    155: }
                    156: /* }}} */
                    157: 
                    158: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
                    159: int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
                    160: int spl_array_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
                    161: 
                    162: /* {{{ spl_array_object_new_ex */
                    163: 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)
                    164: {
                    165:        zend_object_value retval;
                    166:        spl_array_object *intern;
                    167:        zval *tmp;
                    168:        zend_class_entry * parent = class_type;
                    169:        int inherited = 0;
                    170: 
                    171:        intern = emalloc(sizeof(spl_array_object));
                    172:        memset(intern, 0, sizeof(spl_array_object));
                    173:        *obj = intern;
                    174:        ALLOC_INIT_ZVAL(intern->retval);
                    175: 
                    176:        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
                    177:        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    178: 
                    179:        intern->ar_flags = 0;
                    180:        intern->serialize_data   = NULL;
                    181:        intern->unserialize_data = NULL;
                    182:        intern->debug_info       = NULL;
                    183:        intern->ce_get_iterator = spl_ce_ArrayIterator;
                    184:        if (orig) {
                    185:                spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
                    186: 
                    187:                intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
                    188:                intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
                    189:                intern->ce_get_iterator = other->ce_get_iterator;
                    190:                if (clone_orig) {
                    191:                        intern->array = other->array;
                    192:                        if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
                    193:                                MAKE_STD_ZVAL(intern->array);
                    194:                                array_init(intern->array);
                    195:                                zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
                    196:                        }
                    197:                        if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
                    198:                                Z_ADDREF_P(other->array);
                    199:                        }
                    200:                } else {
                    201:                        intern->array = orig;
                    202:                        Z_ADDREF_P(intern->array);
                    203:                        intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
                    204:                }
                    205:        } else {
                    206:                MAKE_STD_ZVAL(intern->array);
                    207:                array_init(intern->array);
                    208:                intern->ar_flags &= ~SPL_ARRAY_IS_REF;
                    209:        }
                    210: 
                    211:        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);
                    212:        while (parent) {
                    213:                if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
                    214:                        retval.handlers = &spl_handler_ArrayIterator;
                    215:                        class_type->get_iterator = spl_array_get_iterator;
                    216:                        break;
                    217:                } else if (parent == spl_ce_ArrayObject) {
                    218:                        retval.handlers = &spl_handler_ArrayObject;
                    219:                        break;
                    220:                }
                    221:                parent = parent->parent;
                    222:                inherited = 1;
                    223:        }
                    224:        if (!parent) { /* this must never happen */
                    225:                php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
                    226:        }
                    227:        if (inherited) {
                    228:                zend_hash_find(&class_type->function_table, "offsetget",    sizeof("offsetget"),    (void **) &intern->fptr_offset_get);
                    229:                if (intern->fptr_offset_get->common.scope == parent) {
                    230:                        intern->fptr_offset_get = NULL;
                    231:                }
                    232:                zend_hash_find(&class_type->function_table, "offsetset",    sizeof("offsetset"),    (void **) &intern->fptr_offset_set);
                    233:                if (intern->fptr_offset_set->common.scope == parent) {
                    234:                        intern->fptr_offset_set = NULL;
                    235:                }
                    236:                zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
                    237:                if (intern->fptr_offset_has->common.scope == parent) {
                    238:                        intern->fptr_offset_has = NULL;
                    239:                }
                    240:                zend_hash_find(&class_type->function_table, "offsetunset",  sizeof("offsetunset"),  (void **) &intern->fptr_offset_del);
                    241:                if (intern->fptr_offset_del->common.scope == parent) {
                    242:                        intern->fptr_offset_del = NULL;
                    243:                }
                    244:                zend_hash_find(&class_type->function_table, "count",        sizeof("count"),        (void **) &intern->fptr_count);
                    245:                if (intern->fptr_count->common.scope == parent) {
                    246:                        intern->fptr_count = NULL;
                    247:                }
                    248:                zend_hash_find(&class_type->function_table, "serialize",    sizeof("serialize"),    (void **) &intern->fptr_serialize);
                    249:                if (intern->fptr_serialize->common.scope == parent) {
                    250:                        intern->fptr_serialize = NULL;
                    251:                }
                    252:                zend_hash_find(&class_type->function_table, "unserialize",  sizeof("unserialize"),  (void **) &intern->fptr_unserialize);
                    253:                if (intern->fptr_unserialize->common.scope == parent) {
                    254:                        intern->fptr_unserialize = NULL;
                    255:                }
                    256:        }
                    257:        /* Cache iterator functions if ArrayIterator or derived. Check current's */
                    258:        /* cache since only current is always required */
                    259:        if (retval.handlers == &spl_handler_ArrayIterator) {
                    260:                if (!class_type->iterator_funcs.zf_current) {
                    261:                        zend_hash_find(&class_type->function_table, "rewind",  sizeof("rewind"),  (void **) &class_type->iterator_funcs.zf_rewind);
                    262:                        zend_hash_find(&class_type->function_table, "valid",   sizeof("valid"),   (void **) &class_type->iterator_funcs.zf_valid);
                    263:                        zend_hash_find(&class_type->function_table, "key",     sizeof("key"),     (void **) &class_type->iterator_funcs.zf_key);
                    264:                        zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
                    265:                        zend_hash_find(&class_type->function_table, "next",    sizeof("next"),    (void **) &class_type->iterator_funcs.zf_next);
                    266:                }
                    267:                if (inherited) {
                    268:                        if (class_type->iterator_funcs.zf_rewind->common.scope  != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
                    269:                        if (class_type->iterator_funcs.zf_valid->common.scope   != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
                    270:                        if (class_type->iterator_funcs.zf_key->common.scope     != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
                    271:                        if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
                    272:                        if (class_type->iterator_funcs.zf_next->common.scope    != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
                    273:                }
                    274:        }
                    275: 
                    276:        spl_array_rewind(intern TSRMLS_CC);
                    277:        return retval;
                    278: }
                    279: /* }}} */
                    280: 
                    281: /* {{{ spl_array_object_new */
                    282: static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
                    283: {
                    284:        spl_array_object *tmp;
                    285:        return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
                    286: }
                    287: /* }}} */
                    288: 
                    289: /* {{{ spl_array_object_clone */
                    290: static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
                    291: {
                    292:        zend_object_value new_obj_val;
                    293:        zend_object *old_object;
                    294:        zend_object *new_object;
                    295:        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
                    296:        spl_array_object *intern;
                    297: 
                    298:        old_object = zend_objects_get_address(zobject TSRMLS_CC);
                    299:        new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
                    300:        new_object = &intern->std;
                    301: 
                    302:        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
                    303: 
                    304:        return new_obj_val;
                    305: }
                    306: /* }}} */
                    307: 
                    308: static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
                    309: {
                    310:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    311:        zval **retval;
                    312:        long index;
                    313:        HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    314: 
                    315: /*  We cannot get the pointer pointer so we don't allow it here for now
                    316:        if (check_inherited && intern->fptr_offset_get) {
                    317:                return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
                    318:        }*/
                    319: 
                    320:        if (!offset) {
                    321:                return &EG(uninitialized_zval_ptr);
                    322:        }
                    323:        
                    324:        if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
                    325:                zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    326:                return &EG(uninitialized_zval_ptr);;
                    327:        }
                    328: 
                    329:        switch(Z_TYPE_P(offset)) {
                    330:        case IS_STRING:
                    331:                if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
                    332:                        if (type == BP_VAR_W || type == BP_VAR_RW) {
                    333:                                zval *value;
                    334:                                ALLOC_INIT_ZVAL(value);
                    335:                                zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
                    336:                                zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval);
                    337:                                return retval;
                    338:                        } else {
                    339:                                zend_error(E_NOTICE, "Undefined index:  %s", Z_STRVAL_P(offset));
                    340:                                return &EG(uninitialized_zval_ptr);
                    341:                        }
                    342:                } else {
                    343:                        return retval;
                    344:                }
                    345:        case IS_DOUBLE:
                    346:        case IS_RESOURCE:
                    347:        case IS_BOOL: 
                    348:        case IS_LONG: 
                    349:                if (offset->type == IS_DOUBLE) {
                    350:                        index = (long)Z_DVAL_P(offset);
                    351:                } else {
                    352:                        index = Z_LVAL_P(offset);
                    353:                }
                    354:                if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
                    355:                        if (type == BP_VAR_W || type == BP_VAR_RW) {
                    356:                                zval *value;
                    357:                                ALLOC_INIT_ZVAL(value);
                    358:                                zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
                    359:                                zend_hash_index_find(ht, index, (void **) &retval);
                    360:                                return retval;
                    361:                        } else {
                    362:                                zend_error(E_NOTICE, "Undefined offset:  %ld", index);
                    363:                                return &EG(uninitialized_zval_ptr);
                    364:                        }
                    365:                } else {
                    366:                        return retval;
                    367:                }
                    368:                break;
                    369:        default:
                    370:                zend_error(E_WARNING, "Illegal offset type");
                    371:                return &EG(uninitialized_zval_ptr);
                    372:        }
                    373: } /* }}} */
                    374: 
                    375: static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
                    376: {
                    377:        zval **ret;
                    378: 
                    379:        if (check_inherited) {
                    380:                spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    381:                if (intern->fptr_offset_get) {
                    382:                        zval *rv;
                    383:                        SEPARATE_ARG_IF_REF(offset);
                    384:                        zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset); 
                    385:                        zval_ptr_dtor(&offset);
                    386:                        if (rv) {
                    387:                                zval_ptr_dtor(&intern->retval);
                    388:                                MAKE_STD_ZVAL(intern->retval);
                    389:                                ZVAL_ZVAL(intern->retval, rv, 1, 1);
                    390:                                return intern->retval;
                    391:                        }
                    392:                        return EG(uninitialized_zval_ptr);
                    393:                }
                    394:        }
                    395:        ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
                    396: 
                    397:        /* When in a write context,
                    398:         * ZE has to be fooled into thinking this is in a reference set
                    399:         * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
                    400:        if ((type == BP_VAR_W || type == BP_VAR_RW) && !Z_ISREF_PP(ret)) {
                    401:                if (Z_REFCOUNT_PP(ret) > 1) {
                    402:                        zval *newval;
                    403: 
                    404:                        /* Separate */
                    405:                        MAKE_STD_ZVAL(newval);
                    406:                        *newval = **ret;
                    407:                        zval_copy_ctor(newval);
                    408:                        Z_SET_REFCOUNT_P(newval, 1);
                    409: 
                    410:                        /* Replace */
                    411:                        Z_DELREF_PP(ret);
                    412:                        *ret = newval;
                    413:                }
                    414: 
                    415:                Z_SET_ISREF_PP(ret);
                    416:        }
                    417: 
                    418:        return *ret;
                    419: } /* }}} */
                    420: 
                    421: static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
                    422: {
                    423:        return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
                    424: } /* }}} */
                    425: 
                    426: static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
                    427: {
                    428:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    429:        long index;
                    430:        HashTable *ht;
                    431: 
                    432:        if (check_inherited && intern->fptr_offset_set) {
                    433:                if (!offset) {
                    434:                        ALLOC_INIT_ZVAL(offset);
                    435:                } else {
                    436:                        SEPARATE_ARG_IF_REF(offset);
                    437:                }
                    438:                zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
                    439:                zval_ptr_dtor(&offset);
                    440:                return;
                    441:        }
                    442:        
                    443:        if (!offset) {
                    444:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    445:                if (ht->nApplyCount > 0) {
                    446:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    447:                        return;
                    448:                }
                    449:                Z_ADDREF_P(value);
                    450:                zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
                    451:                return;
                    452:        }
                    453:        switch(Z_TYPE_P(offset)) {
                    454:        case IS_STRING:
                    455:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    456:                if (ht->nApplyCount > 0) {
                    457:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    458:                        return;
                    459:                }
                    460:                Z_ADDREF_P(value);
                    461:                zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
                    462:                return;
                    463:        case IS_DOUBLE:
                    464:        case IS_RESOURCE:
                    465:        case IS_BOOL: 
                    466:        case IS_LONG: 
                    467:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    468:                if (ht->nApplyCount > 0) {
                    469:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    470:                        return;
                    471:                }
                    472:                if (offset->type == IS_DOUBLE) {
                    473:                        index = (long)Z_DVAL_P(offset);
                    474:                } else {
                    475:                        index = Z_LVAL_P(offset);
                    476:                }
                    477:                Z_ADDREF_P(value);
                    478:                zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
                    479:                return;
                    480:        case IS_NULL:
                    481:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    482:                if (ht->nApplyCount > 0) {
                    483:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    484:                        return;
                    485:                }
                    486:                Z_ADDREF_P(value);
                    487:                zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
                    488:                return;
                    489:        default:
                    490:                zend_error(E_WARNING, "Illegal offset type");
                    491:                return;
                    492:        }
                    493: } /* }}} */
                    494: 
                    495: static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
                    496: {
                    497:        spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
                    498: } /* }}} */
                    499: 
                    500: static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
                    501: {
                    502:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    503:        long index;
                    504:        HashTable *ht;
                    505: 
                    506:        if (check_inherited && intern->fptr_offset_del) {
                    507:                SEPARATE_ARG_IF_REF(offset);
                    508:                zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
                    509:                zval_ptr_dtor(&offset);
                    510:                return;
                    511:        }
                    512: 
                    513:        switch(Z_TYPE_P(offset)) {
                    514:        case IS_STRING:
                    515:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    516:                if (ht->nApplyCount > 0) {
                    517:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    518:                        return;
                    519:                }
                    520:                if (ht == &EG(symbol_table)) {
                    521:                        if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
                    522:                                zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
                    523:                        }
                    524:                } else {
                    525:                        if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
                    526:                                zend_error(E_NOTICE,"Undefined index:  %s", Z_STRVAL_P(offset));
                    527:                        }
                    528:                }
                    529:                break;
                    530:        case IS_DOUBLE:
                    531:        case IS_RESOURCE:
                    532:        case IS_BOOL: 
                    533:        case IS_LONG: 
                    534:                if (offset->type == IS_DOUBLE) {
                    535:                        index = (long)Z_DVAL_P(offset);
                    536:                } else {
                    537:                        index = Z_LVAL_P(offset);
                    538:                }
                    539:                ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    540:                if (ht->nApplyCount > 0) {
                    541:                        zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
                    542:                        return;
                    543:                }
                    544:                if (zend_hash_index_del(ht, index) == FAILURE) {
                    545:                        zend_error(E_NOTICE,"Undefined offset:  %ld", Z_LVAL_P(offset));
                    546:                }
                    547:                break;
                    548:        default:
                    549:                zend_error(E_WARNING, "Illegal offset type");
                    550:                return;
                    551:        }
                    552:        spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
                    553: } /* }}} */
                    554: 
                    555: static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
                    556: {
                    557:        spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
                    558: } /* }}} */
                    559: 
                    560: static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
                    561: {
                    562:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    563:        long index;
                    564:        zval *rv, **tmp;
                    565: 
                    566:        if (check_inherited && intern->fptr_offset_has) {
                    567:                SEPARATE_ARG_IF_REF(offset);
                    568:                zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
                    569:                zval_ptr_dtor(&offset);
                    570:                if (rv && zend_is_true(rv)) {
                    571:                        zval_ptr_dtor(&rv);
                    572:                        return 1;
                    573:                }
                    574:                if (rv) {
                    575:                        zval_ptr_dtor(&rv);
                    576:                }
                    577:                return 0;
                    578:        }
                    579:        
                    580:        switch(Z_TYPE_P(offset)) {
                    581:        case IS_STRING:
                    582:                if (check_empty) {
                    583:                        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) {
                    584:                                switch (check_empty) {
                    585:                                        case 0:
                    586:                                                return Z_TYPE_PP(tmp) != IS_NULL;
                    587:                                        case 2:
                    588:                                                return 1;
                    589:                                        default:
                    590:                                                return zend_is_true(*tmp);
                    591:                                }
                    592:                        }
                    593:                        return 0;
                    594:                } else {
                    595:                        return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
                    596:                }
                    597:        case IS_DOUBLE:
                    598:        case IS_RESOURCE:
                    599:        case IS_BOOL: 
                    600:        case IS_LONG: 
                    601:                if (offset->type == IS_DOUBLE) {
                    602:                        index = (long)Z_DVAL_P(offset);
                    603:                } else {
                    604:                        index = Z_LVAL_P(offset);
                    605:                }
                    606:                if (check_empty) {
                    607:                        HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    608:                        if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
                    609:                                switch (check_empty) {
                    610:                                        case 0:
                    611:                                                return Z_TYPE_PP(tmp) != IS_NULL;
                    612:                                        case 2:
                    613:                                                return 1;
                    614:                                        default:
                    615:                                                return zend_is_true(*tmp);
                    616:                                }
                    617:                        }
                    618:                        return 0;
                    619:                } else {
                    620:                        return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
                    621:                }
                    622:        default:
                    623:                zend_error(E_WARNING, "Illegal offset type");
                    624:        }
                    625:        return 0;
                    626: } /* }}} */
                    627: 
                    628: static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
                    629: {
                    630:        return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
                    631: } /* }}} */
                    632: 
                    633: /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
                    634:        proto bool ArrayIterator::offsetExists(mixed $index)
                    635:    Returns whether the requested $index exists. */
                    636: SPL_METHOD(Array, offsetExists)
                    637: {
                    638:        zval *index;
                    639:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
                    640:                return;
                    641:        }
                    642:        RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
                    643: } /* }}} */
                    644: 
                    645: /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
                    646:        proto mixed ArrayIterator::offsetGet(mixed $index)
                    647:    Returns the value at the specified $index. */
                    648: SPL_METHOD(Array, offsetGet)
                    649: {
                    650:        zval *index, *value;
                    651:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
                    652:                return;
                    653:        }
                    654:        value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
                    655:        RETURN_ZVAL(value, 1, 0);
                    656: } /* }}} */
                    657: 
                    658: /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
                    659:        proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
                    660:    Sets the value at the specified $index to $newval. */
                    661: SPL_METHOD(Array, offsetSet)
                    662: {
                    663:        zval *index, *value;
                    664:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
                    665:                return;
                    666:        }
                    667:        spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
                    668: } /* }}} */
                    669: 
                    670: 
                    671: void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
                    672: {
                    673:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    674:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    675: 
                    676:        if (!aht) {
                    677:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                    678:                return;
                    679:        }
                    680:        
                    681:        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
                    682:                php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
                    683:                return;
                    684:        }
                    685: 
                    686:        spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
                    687:        if (!intern->pos) {
                    688:                spl_array_set_pos(intern, aht->pListTail);
                    689:        }
                    690: } /* }}} */
                    691: 
                    692: /* {{{ proto void ArrayObject::append(mixed $newval)
                    693:        proto void ArrayIterator::append(mixed $newval)
                    694:    Appends the value (cannot be called for objects). */
                    695: SPL_METHOD(Array, append)
                    696: {
                    697:        zval *value;
                    698: 
                    699:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
                    700:                return;
                    701:        }
                    702:        spl_array_iterator_append(getThis(), value TSRMLS_CC);
                    703: } /* }}} */
                    704: 
                    705: /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
                    706:        proto void ArrayIterator::offsetUnset(mixed $index)
                    707:    Unsets the value at the specified $index. */
                    708: SPL_METHOD(Array, offsetUnset)
                    709: {
                    710:        zval *index;
                    711:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
                    712:                return;
                    713:        }
                    714:        spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
                    715: } /* }}} */
                    716: 
                    717: /* {{{ proto array ArrayObject::getArrayCopy()
                    718:       proto array ArrayIterator::getArrayCopy()
                    719:    Return a copy of the contained array */
                    720: SPL_METHOD(Array, getArrayCopy)
                    721: {
                    722:        zval *object = getThis(), *tmp;
                    723:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    724:     
                    725:     array_init(return_value);
                    726:        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*));
                    727: } /* }}} */
                    728: 
                    729: static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
                    730: {
                    731:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    732:        HashTable *result;
                    733: 
                    734:        if (intern->nApplyCount > 1) {
                    735:                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
                    736:        }
                    737: 
                    738:        intern->nApplyCount++;
                    739:        result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
                    740:        intern->nApplyCount--;
                    741:        return result;
                    742: } /* }}} */
                    743: 
                    744: static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
                    745: {
                    746:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
                    747:        zval *tmp, *storage;
                    748:        int name_len;
                    749:        char *zname;
                    750:        zend_class_entry *base;
                    751: 
                    752:        *is_temp = 0;
                    753: 
                    754:        if (HASH_OF(intern->array) == intern->std.properties) {
                    755:                return intern->std.properties;
                    756:        } else {
                    757:                if (intern->debug_info == NULL) {
                    758:                        ALLOC_HASHTABLE(intern->debug_info);
                    759:                        ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
                    760:                }
                    761: 
                    762:                if (intern->debug_info->nApplyCount == 0) {
                    763:                        zend_hash_clean(intern->debug_info);
                    764:                        zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    765: 
                    766:                        storage = intern->array;
                    767:                        zval_add_ref(&storage);
                    768: 
                    769:                        base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
                    770:                        zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
                    771:                        zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
                    772:                        efree(zname);
                    773:                }
                    774: 
                    775:                return intern->debug_info;
                    776:        }
                    777: }
                    778: /* }}} */
                    779: 
                    780: static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
                    781: {
                    782:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    783: 
                    784:        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
                    785:        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
                    786:                return spl_array_read_dimension(object, member, type TSRMLS_CC);
                    787:        }
                    788:        return std_object_handlers.read_property(object, member, type TSRMLS_CC);
                    789: } /* }}} */
                    790: 
                    791: static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
                    792: {
                    793:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    794: 
                    795:        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
                    796:        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
                    797:                spl_array_write_dimension(object, member, value TSRMLS_CC);
                    798:                return;
                    799:        }
                    800:        std_object_handlers.write_property(object, member, value TSRMLS_CC);
                    801: } /* }}} */
                    802: 
                    803: static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    804: {
                    805:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    806: 
                    807:        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
                    808:        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
                    809:                return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC);
                    810:        }
                    811:        return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
                    812: } /* }}} */
                    813: 
                    814: static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
                    815: {
                    816:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    817: 
                    818:        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
                    819:        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
                    820:                return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
                    821:        }
                    822:        return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
                    823: 
                    824: } /* }}} */
                    825: 
                    826: static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    827: {
                    828:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                    829: 
                    830:        if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
                    831:        && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
                    832:                spl_array_unset_dimension(object, member TSRMLS_CC);
                    833:                spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
                    834:                return;
                    835:        }
                    836:        std_object_handlers.unset_property(object, member TSRMLS_CC);
                    837: } /* }}} */
                    838: 
                    839: static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
                    840: {
                    841:        char *string_key;
                    842:        uint string_length;
                    843:        ulong num_key;
                    844: 
                    845:        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
                    846:                do {
                    847:                        if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
                    848:                                if (!string_length || string_key[0]) {
                    849:                                        return SUCCESS;
                    850:                                }
                    851:                        } else {
                    852:                                return SUCCESS;
                    853:                        }
                    854:                        if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
                    855:                                return FAILURE;
                    856:                        }
                    857:                        zend_hash_move_forward_ex(aht, &intern->pos);
                    858:                        spl_array_update_pos(intern);
                    859:                } while (1);
                    860:        }
                    861:        return FAILURE;
                    862: } /* }}} */
                    863: 
                    864: static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
                    865: {
                    866:        zend_hash_move_forward_ex(aht, &intern->pos);
                    867:        spl_array_update_pos(intern);
                    868:        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
                    869:                return spl_array_skip_protected(intern, aht TSRMLS_CC);
                    870:        } else {
                    871:                return zend_hash_has_more_elements_ex(aht, &intern->pos);
                    872:        }
                    873: } /* }}} */
                    874: 
                    875: static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
                    876: {
                    877:        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                    878:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                    879:                return FAILURE;
                    880:        }
                    881: 
                    882:        return spl_array_next_no_verify(intern, aht TSRMLS_CC);
                    883: } /* }}} */
                    884: 
                    885: static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
                    886: {
                    887:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                    888: 
                    889:        return spl_array_next_ex(intern, aht TSRMLS_CC);
                    890: 
                    891: } /* }}} */
                    892: 
                    893: /* define an overloaded iterator structure */
                    894: typedef struct {
                    895:        zend_user_iterator    intern;
                    896:        spl_array_object      *object;
                    897: } spl_array_it;
                    898: 
                    899: static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                    900: {
                    901:        spl_array_it *iterator = (spl_array_it *)iter;
                    902: 
                    903:        zend_user_it_invalidate_current(iter TSRMLS_CC);
                    904:        zval_ptr_dtor((zval**)&iterator->intern.it.data);
                    905: 
                    906:        efree(iterator);
                    907: }
                    908: /* }}} */
                    909:        
                    910: static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                    911: {
                    912:        spl_array_it       *iterator = (spl_array_it *)iter;
                    913:        spl_array_object   *object   = iterator->object;
                    914:        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
                    915: 
                    916:        if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
                    917:                return zend_user_it_valid(iter TSRMLS_CC);
                    918:        } else {
                    919:                if (!aht) {
                    920:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
                    921:                        return FAILURE;
                    922:                }
                    923:        
                    924:                if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
                    925:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
                    926:                        return FAILURE;
                    927:                } else {
                    928:                        return zend_hash_has_more_elements_ex(aht, &object->pos);
                    929:                }
                    930:        }
                    931: }
                    932: /* }}} */
                    933: 
                    934: static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
                    935: {
                    936:        spl_array_it       *iterator = (spl_array_it *)iter;
                    937:        spl_array_object   *object   = iterator->object;
                    938:        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
                    939: 
                    940:        if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
                    941:                zend_user_it_get_current_data(iter, data TSRMLS_CC);
                    942:        } else {
                    943:                if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
                    944:                        *data = NULL;
                    945:                }
                    946:        }
                    947: }
                    948: /* }}} */
                    949: 
                    950: static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
                    951: {
                    952:        spl_array_it       *iterator = (spl_array_it *)iter;
                    953:        spl_array_object   *object   = iterator->object;
                    954:        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
                    955: 
                    956:        if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
                    957:                return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
                    958:        } else {
                    959:                if (!aht) {
                    960:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
                    961:                        return HASH_KEY_NON_EXISTANT;
                    962:                }
                    963:        
                    964:                if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
                    965:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
                    966:                        return HASH_KEY_NON_EXISTANT;
                    967:                }
                    968:        
                    969:                return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
                    970:        }
                    971: }
                    972: /* }}} */
                    973: 
                    974: static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                    975: {
                    976:        spl_array_it       *iterator = (spl_array_it *)iter;
                    977:        spl_array_object   *object   = iterator->object;
                    978:        HashTable          *aht      = spl_array_get_hash_table(object, 0 TSRMLS_CC);
                    979: 
                    980:        if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
                    981:                zend_user_it_move_forward(iter TSRMLS_CC);
                    982:        } else {
                    983:                zend_user_it_invalidate_current(iter TSRMLS_CC);
                    984:                if (!aht) {
                    985:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
                    986:                        return;
                    987:                }
                    988:        
                    989:                if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
                    990:                        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
                    991:                } else {
                    992:                        spl_array_next_no_verify(object, aht TSRMLS_CC);
                    993:                }
                    994:        }
                    995: }
                    996: /* }}} */
                    997: 
                    998: static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
                    999: {
                   1000: 
                   1001:        zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
                   1002:        spl_array_update_pos(intern);
                   1003:        spl_array_skip_protected(intern, aht TSRMLS_CC);
                   1004: 
                   1005: } /* }}} */
                   1006: 
                   1007: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
                   1008: {
                   1009:        HashTable          *aht      = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1010: 
                   1011:        if (!aht) {
                   1012:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
                   1013:                return;
                   1014:        }
                   1015: 
                   1016:        spl_array_rewind_ex(intern, aht TSRMLS_CC);
                   1017: }
                   1018: /* }}} */
                   1019: 
                   1020: static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
                   1021: {
                   1022:        spl_array_it       *iterator = (spl_array_it *)iter;
                   1023:        spl_array_object   *object   = iterator->object;
                   1024: 
                   1025:        if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
                   1026:                zend_user_it_rewind(iter TSRMLS_CC);
                   1027:        } else {
                   1028:                zend_user_it_invalidate_current(iter TSRMLS_CC);
                   1029:                spl_array_rewind(object TSRMLS_CC);
                   1030:        }
                   1031: }
                   1032: /* }}} */
                   1033: 
                   1034: /* {{{ spl_array_set_array */
                   1035: static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
                   1036: 
                   1037:        if (Z_TYPE_PP(array) == IS_ARRAY) {
                   1038:                SEPARATE_ZVAL_IF_NOT_REF(array);
                   1039:        }
                   1040: 
                   1041:        if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
                   1042:                zval_ptr_dtor(&intern->array);
                   1043:                if (just_array) {
                   1044:                        spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
                   1045:                        ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
                   1046:                }               
                   1047:                ar_flags |= SPL_ARRAY_USE_OTHER;
                   1048:                intern->array = *array;
                   1049:        } else {
                   1050:                if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
                   1051:                        zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
                   1052:                        return;
                   1053:                }
                   1054:                zval_ptr_dtor(&intern->array);
                   1055:                intern->array = *array;
                   1056:        }
                   1057:        if (object == *array) {
                   1058:                intern->ar_flags |= SPL_ARRAY_IS_SELF;
                   1059:                intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
                   1060:        } else {
                   1061:                intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
                   1062:        }
                   1063:        intern->ar_flags |= ar_flags;
                   1064:        Z_ADDREF_P(intern->array);
                   1065:        if (Z_TYPE_PP(array) == IS_OBJECT) {
                   1066:                zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
                   1067:                if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
                   1068:                || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
                   1069:                        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);
                   1070:                }
                   1071:        }
                   1072: 
                   1073:        spl_array_rewind(intern TSRMLS_CC);
                   1074: }
                   1075: /* }}} */
                   1076: 
                   1077: /* iterator handler table */
                   1078: zend_object_iterator_funcs spl_array_it_funcs = {
                   1079:        spl_array_it_dtor,
                   1080:        spl_array_it_valid,
                   1081:        spl_array_it_get_current_data,
                   1082:        spl_array_it_get_current_key,
                   1083:        spl_array_it_move_forward,
                   1084:        spl_array_it_rewind
                   1085: };
                   1086: 
                   1087: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
                   1088: {
                   1089:        spl_array_it       *iterator;
                   1090:        spl_array_object   *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1091: 
                   1092:        if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
                   1093:                zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
                   1094:        }
                   1095: 
                   1096:        iterator     = emalloc(sizeof(spl_array_it));
                   1097: 
                   1098:        Z_ADDREF_P(object);
                   1099:        iterator->intern.it.data = (void*)object;
                   1100:        iterator->intern.it.funcs = &spl_array_it_funcs;
                   1101:        iterator->intern.ce = ce;
                   1102:        iterator->intern.value = NULL;
                   1103:        iterator->object = array_object;
                   1104:        
                   1105:        return (zend_object_iterator*)iterator;
                   1106: }
                   1107: /* }}} */
                   1108: 
                   1109: /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
                   1110:        proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
                   1111:    Constructs a new array iterator from a path. */
                   1112: SPL_METHOD(Array, __construct)
                   1113: {
                   1114:        zval *object = getThis();
                   1115:        spl_array_object *intern;
                   1116:        zval **array;
                   1117:        long ar_flags = 0;
                   1118:        zend_class_entry *ce_get_iterator = spl_ce_Iterator;
                   1119:        zend_error_handling error_handling;
                   1120: 
                   1121:        if (ZEND_NUM_ARGS() == 0) {
                   1122:                return; /* nothing to do */
                   1123:        }
                   1124: 
                   1125:        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
                   1126: 
                   1127:        intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1128: 
                   1129:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
                   1130:                zend_restore_error_handling(&error_handling TSRMLS_CC);
                   1131:                return;
                   1132:        }
                   1133: 
                   1134:        if (ZEND_NUM_ARGS() > 2) {
                   1135:                intern->ce_get_iterator = ce_get_iterator;
                   1136:        }
                   1137: 
                   1138:        ar_flags &= ~SPL_ARRAY_INT_MASK;
                   1139: 
                   1140:        spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
                   1141: 
                   1142:        zend_restore_error_handling(&error_handling TSRMLS_CC);
                   1143: 
                   1144: }
                   1145:  /* }}} */
                   1146: 
                   1147: /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
                   1148:    Set the class used in getIterator. */
                   1149: SPL_METHOD(Array, setIteratorClass)
                   1150: {
                   1151:        zval *object = getThis();
                   1152:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1153:        zend_class_entry * ce_get_iterator = spl_ce_Iterator;
                   1154: 
                   1155:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
                   1156:                return;
                   1157:        }
                   1158: 
                   1159:        intern->ce_get_iterator = ce_get_iterator;
                   1160: }
                   1161: /* }}} */
                   1162: 
                   1163: /* {{{ proto string ArrayObject::getIteratorClass()
                   1164:    Get the class used in getIterator. */
                   1165: SPL_METHOD(Array, getIteratorClass)
                   1166: {
                   1167:        zval *object = getThis();
                   1168:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1169:        
                   1170:        if (zend_parse_parameters_none() == FAILURE) {
                   1171:                return;
                   1172:        }
                   1173: 
                   1174:        RETURN_STRING(intern->ce_get_iterator->name, 1);
                   1175: }
                   1176: /* }}} */
                   1177: 
                   1178: /* {{{ proto int ArrayObject::getFlags()
                   1179:    Get flags */
                   1180: SPL_METHOD(Array, getFlags)
                   1181: {
                   1182:        zval *object = getThis();
                   1183:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1184:        
                   1185:        if (zend_parse_parameters_none() == FAILURE) {
                   1186:                return;
                   1187:        }
                   1188:        
                   1189:        RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
                   1190: }
                   1191: /* }}} */
                   1192: 
                   1193: /* {{{ proto void ArrayObject::setFlags(int flags)
                   1194:    Set flags */
                   1195: SPL_METHOD(Array, setFlags)
                   1196: {
                   1197:        zval *object = getThis();
                   1198:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1199:        long ar_flags = 0;
                   1200: 
                   1201:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
                   1202:                return;
                   1203:        }
                   1204:        
                   1205:        intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
                   1206: }
                   1207: /* }}} */
                   1208: 
                   1209: /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
                   1210:    Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
                   1211: SPL_METHOD(Array, exchangeArray)
                   1212: {
                   1213:        zval *object = getThis(), *tmp, **array;
                   1214:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1215: 
                   1216:        array_init(return_value);
                   1217:        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*));
                   1218:        
                   1219:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
                   1220:                return;
                   1221:        }
                   1222: 
                   1223:        spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
                   1224: 
                   1225: }
                   1226: /* }}} */
                   1227: 
                   1228: /* {{{ proto ArrayIterator ArrayObject::getIterator()
                   1229:    Create a new iterator from a ArrayObject instance */
                   1230: SPL_METHOD(Array, getIterator)
                   1231: {
                   1232:        zval *object = getThis();
                   1233:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1234:        spl_array_object *iterator;
                   1235:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1236:        
                   1237:        if (zend_parse_parameters_none() == FAILURE) {
                   1238:                return;
                   1239:        }
                   1240: 
                   1241:        if (!aht) {
                   1242:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1243:                return;
                   1244:        }
                   1245: 
                   1246:        return_value->type = IS_OBJECT;
                   1247:        return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
                   1248:        Z_SET_REFCOUNT_P(return_value, 1);
                   1249:        Z_SET_ISREF_P(return_value);
                   1250: }
                   1251: /* }}} */
                   1252: 
                   1253: /* {{{ proto void ArrayIterator::rewind()
                   1254:    Rewind array back to the start */
                   1255: SPL_METHOD(Array, rewind)
                   1256: {
                   1257:        zval *object = getThis();
                   1258:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1259:        
                   1260:        if (zend_parse_parameters_none() == FAILURE) {
                   1261:                return;
                   1262:        }
                   1263: 
                   1264:        spl_array_rewind(intern TSRMLS_CC);
                   1265: }
                   1266: /* }}} */
                   1267: 
                   1268: /* {{{ proto void ArrayIterator::seek(int $position)
                   1269:    Seek to position. */
                   1270: SPL_METHOD(Array, seek)
                   1271: {
                   1272:        long opos, position;
                   1273:        zval *object = getThis();
                   1274:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1275:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1276:        int result;
                   1277: 
                   1278:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
                   1279:                return;
                   1280:        }
                   1281: 
                   1282:        if (!aht) {
                   1283:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1284:                return;
                   1285:        }
                   1286: 
                   1287:        opos = position;
                   1288: 
                   1289:        if (position >= 0) { /* negative values are not supported */
                   1290:                spl_array_rewind(intern TSRMLS_CC);
                   1291:                result = SUCCESS;
                   1292:                
                   1293:                while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
                   1294:        
                   1295:                if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
                   1296:                        return; /* ok */
                   1297:                }
                   1298:        }
                   1299:        zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
                   1300: } /* }}} */
                   1301: 
                   1302: int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
                   1303: {
                   1304:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1305:        HashPosition pos;
                   1306: 
                   1307:        if (!aht) {
                   1308:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1309:                *count = 0;
                   1310:                return FAILURE;
                   1311:        }
                   1312: 
                   1313:        if (Z_TYPE_P(intern->array) == IS_OBJECT) {
                   1314:                /* We need to store the 'pos' since we'll modify it in the functions 
                   1315:                 * we're going to call and which do not support 'pos' as parameter. */
                   1316:                pos = intern->pos;
                   1317:                *count = 0;
                   1318:                spl_array_rewind(intern TSRMLS_CC);
                   1319:                while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
                   1320:                        (*count)++;
                   1321:                }
                   1322:                spl_array_set_pos(intern, pos);
                   1323:                return SUCCESS;
                   1324:        } else {
                   1325:                *count = zend_hash_num_elements(aht);
                   1326:                return SUCCESS;
                   1327:        }
                   1328: } /* }}} */
                   1329: 
                   1330: int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
                   1331: {
                   1332:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1333: 
                   1334:        if (intern->fptr_count) {
                   1335:                zval *rv;
                   1336:                zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
                   1337:                if (rv) {
                   1338:                        zval_ptr_dtor(&intern->retval);
                   1339:                        MAKE_STD_ZVAL(intern->retval);
                   1340:                        ZVAL_ZVAL(intern->retval, rv, 1, 1);
                   1341:                        convert_to_long(intern->retval);
                   1342:                        *count = (long) Z_LVAL_P(intern->retval);
                   1343:                        return SUCCESS;
                   1344:                }
                   1345:                *count = 0;
                   1346:                return FAILURE;
                   1347:        }
                   1348:        return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
                   1349: } /* }}} */
                   1350: 
                   1351: /* {{{ proto int ArrayObject::count()
                   1352:        proto int ArrayIterator::count()
                   1353:    Return the number of elements in the Iterator. */
                   1354: SPL_METHOD(Array, count)
                   1355: {
                   1356:        long count;
                   1357:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1358:        
                   1359:        if (zend_parse_parameters_none() == FAILURE) {
                   1360:                return;
                   1361:        }
                   1362: 
                   1363:        spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
                   1364: 
                   1365:        RETURN_LONG(count);
                   1366: } /* }}} */
                   1367: 
                   1368: static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
                   1369: {
                   1370:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1371:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1372:        zval *tmp, *arg;
                   1373:        zval *retval_ptr = NULL;
                   1374:        
                   1375:        MAKE_STD_ZVAL(tmp);
                   1376:        Z_TYPE_P(tmp) = IS_ARRAY;
                   1377:        Z_ARRVAL_P(tmp) = aht;
                   1378:        
                   1379:        if (use_arg) {
                   1380:                if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
                   1381:                        Z_TYPE_P(tmp) = IS_NULL;
                   1382:                        zval_ptr_dtor(&tmp);
                   1383:                        zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
                   1384:                        return;
                   1385:                }
                   1386:                aht->nApplyCount++;
                   1387:                zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
                   1388:                aht->nApplyCount--;
                   1389:        } else {
                   1390:                aht->nApplyCount++;
                   1391:                zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
                   1392:                aht->nApplyCount--;
                   1393:        }
                   1394:        Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
                   1395:        zval_ptr_dtor(&tmp);
                   1396:        if (retval_ptr) {
                   1397:                COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
                   1398:        }
                   1399: } /* }}} */
                   1400: 
                   1401: #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
                   1402: SPL_METHOD(cname, fname) \
                   1403: { \
                   1404:        spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
                   1405: }
                   1406: 
                   1407: /* {{{ proto int ArrayObject::asort()
                   1408:        proto int ArrayIterator::asort()
                   1409:    Sort the entries by values. */
                   1410: SPL_ARRAY_METHOD(Array, asort, 0) /* }}} */
                   1411: 
                   1412: /* {{{ proto int ArrayObject::ksort()
                   1413:        proto int ArrayIterator::ksort()
                   1414:    Sort the entries by key. */
                   1415: SPL_ARRAY_METHOD(Array, ksort, 0) /* }}} */
                   1416: 
                   1417: /* {{{ proto int ArrayObject::uasort(callback cmp_function)
                   1418:        proto int ArrayIterator::uasort(callback cmp_function)
                   1419:    Sort the entries by values user defined function. */
                   1420: SPL_ARRAY_METHOD(Array, uasort, 1) /* }}} */
                   1421: 
                   1422: /* {{{ proto int ArrayObject::uksort(callback cmp_function)
                   1423:        proto int ArrayIterator::uksort(callback cmp_function)
                   1424:    Sort the entries by key using user defined function. */
                   1425: SPL_ARRAY_METHOD(Array, uksort, 1) /* }}} */
                   1426: 
                   1427: /* {{{ proto int ArrayObject::natsort()
                   1428:        proto int ArrayIterator::natsort()
                   1429:    Sort the entries by values using "natural order" algorithm. */
                   1430: SPL_ARRAY_METHOD(Array, natsort, 0) /* }}} */
                   1431: 
                   1432: /* {{{ proto int ArrayObject::natcasesort()
                   1433:        proto int ArrayIterator::natcasesort()
                   1434:    Sort the entries by key using case insensitive "natural order" algorithm. */
                   1435: SPL_ARRAY_METHOD(Array, natcasesort, 0) /* }}} */
                   1436: 
                   1437: /* {{{ proto mixed|NULL ArrayIterator::current()
                   1438:    Return current array entry */
                   1439: SPL_METHOD(Array, current)
                   1440: {
                   1441:        zval *object = getThis();
                   1442:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1443:        zval **entry;
                   1444:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1445:        
                   1446:        if (zend_parse_parameters_none() == FAILURE) {
                   1447:                return;
                   1448:        }
                   1449: 
                   1450:        if (!aht) {
                   1451:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1452:                return;
                   1453:        }
                   1454: 
                   1455:        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                   1456:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                   1457:                return;
                   1458:        }
                   1459: 
                   1460:        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
                   1461:                return;
                   1462:        }
                   1463:        RETVAL_ZVAL(*entry, 1, 0);
                   1464: }
                   1465: /* }}} */
                   1466: 
                   1467: /* {{{ proto mixed|NULL ArrayIterator::key()
                   1468:    Return current array key */
                   1469: SPL_METHOD(Array, key)
                   1470: {
                   1471:        if (zend_parse_parameters_none() == FAILURE) {
                   1472:                return;
                   1473:        }
                   1474:        
                   1475:        spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
                   1476: } /* }}} */
                   1477: 
                   1478: void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
                   1479: {
                   1480:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1481:        char *string_key;
                   1482:        uint string_length;
                   1483:        ulong num_key;
                   1484:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1485: 
                   1486:        if (!aht) {
                   1487:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1488:                return;
                   1489:        }
                   1490: 
                   1491:        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                   1492:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                   1493:                return;
                   1494:        }
                   1495: 
                   1496:        switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
                   1497:                case HASH_KEY_IS_STRING:
                   1498:                        RETVAL_STRINGL(string_key, string_length - 1, 0);
                   1499:                        break;
                   1500:                case HASH_KEY_IS_LONG:
                   1501:                        RETVAL_LONG(num_key);
                   1502:                        break;
                   1503:                case HASH_KEY_NON_EXISTANT:
                   1504:                        return;
                   1505:        }
                   1506: }
                   1507: /* }}} */
                   1508: 
                   1509: /* {{{ proto void ArrayIterator::next()
                   1510:    Move to next entry */
                   1511: SPL_METHOD(Array, next)
                   1512: {
                   1513:        zval *object = getThis();
                   1514:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1515:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1516: 
                   1517:        if (zend_parse_parameters_none() == FAILURE) {
                   1518:                return;
                   1519:        }
                   1520:        
                   1521:        if (!aht) {
                   1522:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1523:                return;
                   1524:        }
                   1525: 
                   1526:        spl_array_next_ex(intern, aht TSRMLS_CC);
                   1527: }
                   1528: /* }}} */ 
                   1529: 
                   1530: /* {{{ proto bool ArrayIterator::valid()
                   1531:    Check whether array contains more entries */
                   1532: SPL_METHOD(Array, valid)
                   1533: {
                   1534:        zval *object = getThis();
                   1535:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1536:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1537: 
                   1538:        if (zend_parse_parameters_none() == FAILURE) {
                   1539:                return;
                   1540:        }
                   1541:        
                   1542:        if (!aht) {
                   1543:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1544:                return;
                   1545:        }
                   1546: 
                   1547:        if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                   1548:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                   1549:                RETURN_FALSE;
                   1550:        } else {
                   1551:                RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
                   1552:        }
                   1553: }
                   1554: /* }}} */
                   1555: 
                   1556: /* {{{ proto bool RecursiveArrayIterator::hasChildren()
                   1557:    Check whether current element has children (e.g. is an array) */
                   1558: SPL_METHOD(Array, hasChildren)
                   1559: {
                   1560:        zval *object = getThis(), **entry;
                   1561:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1562:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1563:        
                   1564:        if (zend_parse_parameters_none() == FAILURE) {
                   1565:                return;
                   1566:        }
                   1567:        
                   1568:        if (!aht) {
                   1569:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1570:                RETURN_FALSE;
                   1571:        }
                   1572: 
                   1573:        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                   1574:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                   1575:                RETURN_FALSE;
                   1576:        }
                   1577: 
                   1578:        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
                   1579:                RETURN_FALSE;
                   1580:        }
                   1581: 
                   1582:        RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
                   1583: }
                   1584: /* }}} */
                   1585: 
                   1586: /* {{{ proto object RecursiveArrayIterator::getChildren()
                   1587:    Create a sub iterator for the current element (same class as $this) */
                   1588: SPL_METHOD(Array, getChildren)
                   1589: {
                   1590:        zval *object = getThis(), **entry, *flags;
                   1591:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1592:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1593:        
                   1594:        if (zend_parse_parameters_none() == FAILURE) {
                   1595:                return;
                   1596:        }
                   1597: 
                   1598:        if (!aht) {
                   1599:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1600:                return;
                   1601:        }
                   1602: 
                   1603:        if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
                   1604:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
                   1605:                return;
                   1606:        }
                   1607: 
                   1608:        if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
                   1609:                return;
                   1610:        }
                   1611: 
                   1612:        if (Z_TYPE_PP(entry) == IS_OBJECT) {
                   1613:                if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
                   1614:                        return;
                   1615:                }
                   1616:                if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
                   1617:                        RETURN_ZVAL(*entry, 0, 0);
                   1618:                }
                   1619:        }
                   1620: 
                   1621:        MAKE_STD_ZVAL(flags);
                   1622:        ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
                   1623:        spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
                   1624:        zval_ptr_dtor(&flags);
                   1625: }
                   1626: /* }}} */
                   1627: 
                   1628: smart_str spl_array_serialize_helper(spl_array_object *intern, php_serialize_data_t *var_hash_p TSRMLS_DC) { /* {{{ */
                   1629:        HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
                   1630:        zval members, *pmembers;
                   1631:        smart_str buf = {0};
                   1632:        zval *flags;
                   1633:        
                   1634:        if (!aht) {
                   1635:                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
                   1636:                return buf;
                   1637:        }
                   1638: 
                   1639:        MAKE_STD_ZVAL(flags);
                   1640:        ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
                   1641: 
                   1642:        /* storage */
                   1643:        smart_str_appendl(&buf, "x:", 2);
                   1644:        php_var_serialize(&buf, &flags, var_hash_p TSRMLS_CC);
                   1645:        zval_ptr_dtor(&flags);
                   1646: 
                   1647:        if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
                   1648:                php_var_serialize(&buf, &intern->array, var_hash_p TSRMLS_CC);
                   1649:                smart_str_appendc(&buf, ';');
                   1650:        }
                   1651: 
                   1652:        /* members */
                   1653:        smart_str_appendl(&buf, "m:", 2);
                   1654:        INIT_PZVAL(&members);
                   1655:        Z_ARRVAL(members) = intern->std.properties;
                   1656:        Z_TYPE(members) = IS_ARRAY;
                   1657:        pmembers = &members;
                   1658:        php_var_serialize(&buf, &pmembers, var_hash_p TSRMLS_CC); /* finishes the string */
                   1659: 
                   1660:        /* done */
                   1661:        return buf;
                   1662: }
                   1663: /* }}} */
                   1664: 
                   1665: /* {{{ proto string ArrayObject::serialize()
                   1666:    Serialize the object */
                   1667: SPL_METHOD(Array, serialize)
                   1668: {
                   1669:        zval *object = getThis();
                   1670:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1671:        int was_in_serialize = intern->serialize_data != NULL;
                   1672:        smart_str buf;
                   1673:        
                   1674:        if (zend_parse_parameters_none() == FAILURE) {
                   1675:                return;
                   1676:        }
                   1677: 
                   1678:        if (!was_in_serialize) {
                   1679:                intern->serialize_data = emalloc(sizeof(php_serialize_data_t));
                   1680:                PHP_VAR_SERIALIZE_INIT(*intern->serialize_data);
                   1681:        }
                   1682: 
                   1683:        buf = spl_array_serialize_helper(intern, intern->serialize_data TSRMLS_CC);
                   1684: 
                   1685:        if (!was_in_serialize) {
                   1686:                PHP_VAR_SERIALIZE_DESTROY(*intern->serialize_data);
                   1687:                efree(intern->serialize_data);
                   1688:                intern->serialize_data = NULL;
                   1689:        }
                   1690: 
                   1691:        if (buf.c) {
                   1692:                RETURN_STRINGL(buf.c, buf.len, 0);
                   1693:        }
                   1694: 
                   1695:        RETURN_NULL();
                   1696: } /* }}} */
                   1697: 
                   1698: int spl_array_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
                   1699: {
                   1700:        spl_array_object     *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
                   1701: 
                   1702:        if (intern->fptr_serialize) {
                   1703:                int retval;
                   1704:                php_serialize_data_t *before;
                   1705: 
                   1706:                before = intern->serialize_data;
                   1707:                intern->serialize_data = (php_serialize_data_t *)data;
                   1708: 
                   1709:                retval = zend_user_serialize(object, buffer, buf_len, data TSRMLS_CC);
                   1710: 
                   1711:                intern->serialize_data = before;
                   1712: 
                   1713:                return retval;
                   1714:        } else {
                   1715:                smart_str buf;
                   1716: 
                   1717:                buf = spl_array_serialize_helper(intern, (php_serialize_data_t *)data TSRMLS_CC);
                   1718: 
                   1719:                if (buf.c) {
                   1720:                        *buffer  = (unsigned char*)estrndup(buf.c, buf.len);
                   1721:                        *buf_len = buf.len;
                   1722:                        efree(buf.c);
                   1723:                        return SUCCESS;
                   1724:                } else {
                   1725:                        return FAILURE;
                   1726:                }
                   1727:        }
                   1728: }
                   1729: /* }}} */
                   1730: 
                   1731: 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) /* {{{ */
                   1732: {
                   1733:        const unsigned char *p, *s;
                   1734:        zval *pmembers, *pflags = NULL;
                   1735:        long flags;
                   1736: 
                   1737:        /* storage */
                   1738:        s = p = buf;
                   1739: 
                   1740:        if (*p!= 'x' || *++p != ':') {
                   1741:                goto outexcept;
                   1742:        }
                   1743:        ++p;
                   1744: 
                   1745:        ALLOC_INIT_ZVAL(pflags);
                   1746:        if (!php_var_unserialize(&pflags, &p, s + buf_len, var_hash_p TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
                   1747:                zval_ptr_dtor(&pflags);
                   1748:                goto outexcept;
                   1749:        }
                   1750: 
                   1751:        --p; /* for ';' */
                   1752:        flags = Z_LVAL_P(pflags);
                   1753:        zval_ptr_dtor(&pflags);
                   1754:        /* flags needs to be verified and we also need to verify whether the next
                   1755:         * thing we get is ';'. After that we require an 'm' or somethign else
                   1756:         * where 'm' stands for members and anything else should be an array. If
                   1757:         * neither 'a' or 'm' follows we have an error. */
                   1758: 
                   1759:        if (*p != ';') {
                   1760:                goto outexcept;
                   1761:        }
                   1762:        ++p;
                   1763: 
                   1764:        if (*p!='m') {
                   1765:                if (*p!='a' && *p!='O' && *p!='C') {
                   1766:                        goto outexcept;
                   1767:                }
                   1768:                intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
                   1769:                intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
                   1770:                zval_ptr_dtor(&intern->array);
                   1771:                ALLOC_INIT_ZVAL(intern->array);
                   1772:                if (!php_var_unserialize(&intern->array, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
                   1773:                        goto outexcept;
                   1774:                }
                   1775:        }
                   1776:        if (*p != ';') {
                   1777:                goto outexcept;
                   1778:        }
                   1779:        ++p;
                   1780: 
                   1781:        /* members */
                   1782:        if (*p!= 'm' || *++p != ':') {
                   1783:                goto outexcept;
                   1784:        }
                   1785:        ++p;
                   1786: 
                   1787:        ALLOC_INIT_ZVAL(pmembers);
                   1788:        if (!php_var_unserialize(&pmembers, &p, s + buf_len, var_hash_p TSRMLS_CC)) {
                   1789:                zval_ptr_dtor(&pmembers);
                   1790:                goto outexcept;
                   1791:        }
                   1792: 
                   1793:        /* copy members */
                   1794:        zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
                   1795:        zval_ptr_dtor(&pmembers);
                   1796: 
                   1797:        /* done reading $serialized */
                   1798:        return;
                   1799: 
                   1800: outexcept:
                   1801:        zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - (char *)buf), buf_len);
                   1802:        return;
                   1803: 
                   1804: }
                   1805: /* }}} */
                   1806: 
                   1807: /* {{{ proto void ArrayObject::unserialize(string serialized)
                   1808:    Unserialize the object */
                   1809: SPL_METHOD(Array, unserialize)
                   1810: {
                   1811:        char *buf;
                   1812:        int buf_len;
                   1813:        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1814:        int was_in_unserialize = intern->unserialize_data != NULL;
                   1815: 
                   1816:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
                   1817:                return;
                   1818:        }
                   1819: 
                   1820:        if (buf_len == 0) {
                   1821:                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
                   1822:                return;
                   1823:        }
                   1824: 
                   1825:        if (!was_in_unserialize) {
                   1826:                intern->unserialize_data = emalloc(sizeof(php_unserialize_data_t));
                   1827:                PHP_VAR_UNSERIALIZE_INIT(*intern->unserialize_data);
                   1828:        }
                   1829: 
                   1830:        spl_array_unserialize_helper(intern, (const unsigned char *)buf, buf_len, intern->unserialize_data TSRMLS_CC);
                   1831: 
                   1832:        if (!was_in_unserialize) {
                   1833:                PHP_VAR_UNSERIALIZE_DESTROY(*intern->unserialize_data);
                   1834:                efree(intern->unserialize_data);
                   1835:                intern->unserialize_data = NULL;
                   1836:        }
                   1837: } /* }}} */
                   1838: 
                   1839: int spl_array_unserialize(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC)
                   1840: {
                   1841:        spl_array_object *intern;
                   1842: 
                   1843:        object_init_ex(*object, ce);
                   1844:        intern = (spl_array_object*)zend_object_store_get_object(*object TSRMLS_CC);
                   1845: 
                   1846:        if (intern->fptr_unserialize) {
                   1847:                zval *zdata;
                   1848:                php_unserialize_data_t *before;
                   1849:                MAKE_STD_ZVAL(zdata);
                   1850:                ZVAL_STRINGL(zdata, (char *)buf, buf_len, 1);
                   1851: 
                   1852:                before = intern->unserialize_data;
                   1853:                intern->unserialize_data = (php_unserialize_data_t *)data;
                   1854: 
                   1855:                zend_call_method_with_1_params(object, ce, &ce->unserialize_func, "unserialize", NULL, zdata);
                   1856: 
                   1857:                intern->unserialize_data = before;
                   1858: 
                   1859:                zval_ptr_dtor(&zdata);
                   1860:        } else {
                   1861:                spl_array_unserialize_helper(intern, buf, buf_len, (php_unserialize_data_t *)data TSRMLS_CC);
                   1862:        }
                   1863: 
                   1864:        if (EG(exception)) {
                   1865:                return FAILURE;
                   1866:        } else {
                   1867:                return SUCCESS;
                   1868:        }
                   1869: } 
                   1870: /* }}} */
                   1871: 
                   1872: /* {{{ arginfo and function tbale */
                   1873: ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
                   1874:        ZEND_ARG_INFO(0, array)
                   1875: ZEND_END_ARG_INFO()
                   1876: 
                   1877: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
                   1878:        ZEND_ARG_INFO(0, index)
                   1879: ZEND_END_ARG_INFO()
                   1880: 
                   1881: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
                   1882:        ZEND_ARG_INFO(0, index)
                   1883:        ZEND_ARG_INFO(0, newval)
                   1884: ZEND_END_ARG_INFO()
                   1885: 
                   1886: ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
                   1887:        ZEND_ARG_INFO(0, value)
                   1888: ZEND_END_ARG_INFO()
                   1889: 
                   1890: ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
                   1891:        ZEND_ARG_INFO(0, position)
                   1892: ZEND_END_ARG_INFO()
                   1893: 
                   1894: ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
                   1895:        ZEND_ARG_INFO(0, array)
                   1896: ZEND_END_ARG_INFO()
                   1897: 
                   1898: ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
                   1899:        ZEND_ARG_INFO(0, flags)
                   1900: ZEND_END_ARG_INFO()
                   1901: 
                   1902: ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
                   1903:        ZEND_ARG_INFO(0, iteratorClass)
                   1904: ZEND_END_ARG_INFO()
                   1905: 
                   1906: ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
                   1907:        ZEND_ARG_INFO(0, cmp_function)
                   1908: ZEND_END_ARG_INFO();
                   1909: 
                   1910: ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
                   1911:        ZEND_ARG_INFO(0, serialized)
                   1912: ZEND_END_ARG_INFO();
                   1913: 
                   1914: ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
                   1915: ZEND_END_ARG_INFO()
                   1916: 
                   1917: static const zend_function_entry spl_funcs_ArrayObject[] = {
                   1918:        SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
                   1919:        SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1920:        SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1921:        SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
                   1922:        SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1923:        SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
                   1924:        SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1925:        SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1926:        SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1927:        SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
                   1928:        SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1929:        SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1930:        SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
                   1931:        SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
                   1932:        SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1933:        SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1934:        SPL_ME(Array, unserialize,      arginfo_array_unserialize,      ZEND_ACC_PUBLIC)
                   1935:        SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1936:        /* ArrayObject specific */
                   1937:        SPL_ME(Array, getIterator,      arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1938:        SPL_ME(Array, exchangeArray,    arginfo_array_exchangeArray,    ZEND_ACC_PUBLIC)
                   1939:        SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
                   1940:        SPL_ME(Array, getIteratorClass, arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1941:        PHP_FE_END
                   1942: };
                   1943: 
                   1944: static const zend_function_entry spl_funcs_ArrayIterator[] = {
                   1945:        SPL_ME(Array, __construct,      arginfo_array___construct,      ZEND_ACC_PUBLIC)
                   1946:        SPL_ME(Array, offsetExists,     arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1947:        SPL_ME(Array, offsetGet,        arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1948:        SPL_ME(Array, offsetSet,        arginfo_array_offsetSet,        ZEND_ACC_PUBLIC)
                   1949:        SPL_ME(Array, offsetUnset,      arginfo_array_offsetGet,        ZEND_ACC_PUBLIC)
                   1950:        SPL_ME(Array, append,           arginfo_array_append,           ZEND_ACC_PUBLIC)
                   1951:        SPL_ME(Array, getArrayCopy,     arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1952:        SPL_ME(Array, count,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1953:        SPL_ME(Array, getFlags,         arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1954:        SPL_ME(Array, setFlags,         arginfo_array_setFlags,         ZEND_ACC_PUBLIC)
                   1955:        SPL_ME(Array, asort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1956:        SPL_ME(Array, ksort,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1957:        SPL_ME(Array, uasort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
                   1958:        SPL_ME(Array, uksort,           arginfo_array_uXsort,           ZEND_ACC_PUBLIC)
                   1959:        SPL_ME(Array, natsort,          arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1960:        SPL_ME(Array, natcasesort,      arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1961:        SPL_ME(Array, unserialize,      arginfo_array_unserialize,      ZEND_ACC_PUBLIC)
                   1962:        SPL_ME(Array, serialize,        arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1963:        /* ArrayIterator specific */
                   1964:        SPL_ME(Array, rewind,           arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1965:        SPL_ME(Array, current,          arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1966:        SPL_ME(Array, key,              arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1967:        SPL_ME(Array, next,             arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1968:        SPL_ME(Array, valid,            arginfo_array_void,             ZEND_ACC_PUBLIC)
                   1969:        SPL_ME(Array, seek,             arginfo_array_seek,             ZEND_ACC_PUBLIC)
                   1970:        PHP_FE_END
                   1971: };
                   1972: 
                   1973: static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
                   1974:        SPL_ME(Array, hasChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
                   1975:        SPL_ME(Array, getChildren,   arginfo_array_void, ZEND_ACC_PUBLIC)
                   1976:        PHP_FE_END
                   1977: };
                   1978: /* }}} */
                   1979: 
                   1980: /* {{{ PHP_MINIT_FUNCTION(spl_array) */
                   1981: PHP_MINIT_FUNCTION(spl_array)
                   1982: {
                   1983:        REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
                   1984:        REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
                   1985:        REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
                   1986:        REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
                   1987:        spl_ce_ArrayObject->serialize   = spl_array_serialize;
                   1988:        spl_ce_ArrayObject->unserialize = spl_array_unserialize;
                   1989:        memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
                   1990: 
                   1991:        spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
                   1992:        spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
                   1993:        spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
                   1994:        spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
                   1995:        spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
                   1996:        spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
                   1997: 
                   1998:        spl_handler_ArrayObject.get_properties = spl_array_get_properties;
                   1999:        spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
                   2000:        spl_handler_ArrayObject.read_property = spl_array_read_property;
                   2001:        spl_handler_ArrayObject.write_property = spl_array_write_property;
                   2002:        spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
                   2003:        spl_handler_ArrayObject.has_property = spl_array_has_property;
                   2004:        spl_handler_ArrayObject.unset_property = spl_array_unset_property;
                   2005: 
                   2006:        REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
                   2007:        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
                   2008:        REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
                   2009:        REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
                   2010:        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
                   2011:        spl_ce_ArrayIterator->serialize   = spl_array_serialize;
                   2012:        spl_ce_ArrayIterator->unserialize = spl_array_unserialize;
                   2013:        memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
                   2014:        spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
                   2015:        
                   2016:        REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
                   2017:        REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
                   2018:        spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
                   2019: 
                   2020:        REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
                   2021:        REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
                   2022: 
                   2023:        REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
                   2024:        REGISTER_SPL_CLASS_CONST_LONG(ArrayObject,   "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
                   2025: 
                   2026:        REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST",    SPL_ARRAY_STD_PROP_LIST);
                   2027:        REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS",   SPL_ARRAY_ARRAY_AS_PROPS);
                   2028: 
                   2029:        REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
                   2030: 
                   2031:        return SUCCESS;
                   2032: }
                   2033: /* }}} */
                   2034: 
                   2035: /*
                   2036:  * Local variables:
                   2037:  * tab-width: 4
                   2038:  * c-basic-offset: 4
                   2039:  * End:
                   2040:  * vim600: fdm=marker
                   2041:  * vim: noet sw=4 ts=4
                   2042:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>