Annotation of embedaddon/php/ext/spl/spl_observer.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 SplSubject 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:    |          Etienne Kneuss <colder@php.net>                             |
                     17:    +----------------------------------------------------------------------+
                     18:  */
                     19: 
                     20: /* $Id: spl_observer.c 321634 2012-01-01 13:15:04Z felipe $ */
                     21: 
                     22: #ifdef HAVE_CONFIG_H
                     23: # include "config.h"
                     24: #endif
                     25: 
                     26: #include "php.h"
                     27: #include "php_ini.h"
                     28: #include "ext/standard/info.h"
                     29: #include "ext/standard/php_var.h"
                     30: #include "ext/standard/php_smart_str.h"
                     31: #include "zend_interfaces.h"
                     32: #include "zend_exceptions.h"
                     33: 
                     34: #include "php_spl.h"
                     35: #include "spl_functions.h"
                     36: #include "spl_engine.h"
                     37: #include "spl_observer.h"
                     38: #include "spl_iterators.h"
                     39: #include "spl_array.h"
                     40: #include "spl_exceptions.h"
                     41: 
                     42: SPL_METHOD(SplObserver, update);
                     43: SPL_METHOD(SplSubject, attach);
                     44: SPL_METHOD(SplSubject, detach);
                     45: SPL_METHOD(SplSubject, notify);
                     46: 
                     47: ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0)
                     48:        ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0)
                     49: ZEND_END_ARG_INFO();
                     50: 
                     51: static const zend_function_entry spl_funcs_SplObserver[] = {
                     52:        SPL_ABSTRACT_ME(SplObserver, update,   arginfo_SplObserver_update)
                     53:        {NULL, NULL, NULL}
                     54: };
                     55: 
                     56: ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0)
                     57:        ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0)
                     58: ZEND_END_ARG_INFO();
                     59: 
                     60: ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_void, 0)
                     61: ZEND_END_ARG_INFO();
                     62: 
                     63: /*ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1)
                     64:        ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1)
                     65: ZEND_END_ARG_INFO();*/
                     66: 
                     67: static const zend_function_entry spl_funcs_SplSubject[] = {
                     68:        SPL_ABSTRACT_ME(SplSubject,  attach,   arginfo_SplSubject_attach)
                     69:        SPL_ABSTRACT_ME(SplSubject,  detach,   arginfo_SplSubject_attach)
                     70:        SPL_ABSTRACT_ME(SplSubject,  notify,   arginfo_SplSubject_void)
                     71:        {NULL, NULL, NULL}
                     72: };
                     73: 
                     74: PHPAPI zend_class_entry     *spl_ce_SplObserver;
                     75: PHPAPI zend_class_entry     *spl_ce_SplSubject;
                     76: PHPAPI zend_class_entry     *spl_ce_SplObjectStorage;
                     77: PHPAPI zend_class_entry     *spl_ce_MultipleIterator;
                     78: 
                     79: PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
                     80: 
                     81: typedef struct _spl_SplObjectStorage { /* {{{ */
                     82:        zend_object       std;
                     83:        HashTable         storage;
                     84:        long              index;
                     85:        HashPosition      pos;
                     86:        long              flags;
                     87:        HashTable        *debug_info;
                     88: } spl_SplObjectStorage; /* }}} */
                     89: 
                     90: /* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
                     91: typedef struct _spl_SplObjectStorageElement {
                     92:        zval* obj;
                     93:        zval* inf;
                     94: } spl_SplObjectStorageElement; /* }}} */
                     95: 
                     96: void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
                     97: {
                     98:        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
                     99: 
                    100:        zend_object_std_dtor(&intern->std TSRMLS_CC);
                    101:        
                    102:        zend_hash_destroy(&intern->storage);
                    103:        
                    104:        if (intern->debug_info != NULL) {
                    105:                zend_hash_destroy(intern->debug_info);
                    106:                efree(intern->debug_info);
                    107:        }
                    108: 
                    109:        efree(object);
                    110: } /* }}} */
                    111: 
                    112: static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */
                    113: {
                    114:        zval_ptr_dtor(&element->obj);
                    115:        zval_ptr_dtor(&element->inf);
                    116: } /* }}} */
                    117: 
                    118: 
                    119: spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
                    120: {
                    121:        spl_SplObjectStorageElement *element;
                    122:        zend_object_value *pzvalue;     
                    123: #if HAVE_PACKED_OBJECT_VALUE
                    124:        pzvalue = &Z_OBJVAL_P(obj);
                    125: #else
                    126:        zend_object_value zvalue;
                    127:        memset(&zvalue, 0, sizeof(zend_object_value));
                    128:        zvalue.handle = Z_OBJ_HANDLE_P(obj);
                    129:        zvalue.handlers = Z_OBJ_HT_P(obj);
                    130:        pzvalue = &zvalue;
                    131: #endif
                    132:        if (zend_hash_find(&intern->storage, (char*)pzvalue, sizeof(zend_object_value), (void**)&element) == SUCCESS) {
                    133:                return element;
                    134:        } else {
                    135:                return NULL;
                    136:        }
                    137: } /* }}} */
                    138: 
                    139: void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
                    140: {
                    141:        spl_SplObjectStorageElement *pelement, element;
                    142:        pelement = spl_object_storage_get(intern, obj TSRMLS_CC);
                    143:        if (inf) {
                    144:                Z_ADDREF_P(inf);
                    145:        } else {
                    146:                ALLOC_INIT_ZVAL(inf);
                    147:        }
                    148:        if (pelement) {
                    149:                zval_ptr_dtor(&pelement->inf);
                    150:                pelement->inf = inf;
                    151:                return;
                    152:        }
                    153:        Z_ADDREF_P(obj);
                    154:        element.obj = obj;
                    155:        element.inf = inf;
                    156: #if HAVE_PACKED_OBJECT_VALUE
                    157:        zend_hash_update(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);    
                    158: #else
                    159:        {
                    160:                zend_object_value zvalue;
                    161:                memset(&zvalue, 0, sizeof(zend_object_value));
                    162:                zvalue.handle = Z_OBJ_HANDLE_P(obj);
                    163:                zvalue.handlers = Z_OBJ_HT_P(obj);
                    164:                zend_hash_update(&intern->storage, (char*)&zvalue, sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);
                    165:        }
                    166: #endif
                    167: } /* }}} */
                    168: 
                    169: int spl_object_storage_detach(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
                    170: {
                    171: #if HAVE_PACKED_OBJECT_VALUE
                    172:        return zend_hash_del(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
                    173: #else
                    174:        {
                    175:                zend_object_value zvalue;
                    176:                memset(&zvalue, 0, sizeof(zend_object_value));
                    177:                zvalue.handle = Z_OBJ_HANDLE_P(obj);
                    178:                zvalue.handlers = Z_OBJ_HT_P(obj);
                    179:                return zend_hash_del(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
                    180:        }
                    181: #endif
                    182: } /* }}}*/
                    183: 
                    184: void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
                    185:        HashPosition pos;
                    186:        spl_SplObjectStorageElement *element;
                    187: 
                    188:        zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
                    189:        while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
                    190:                spl_object_storage_attach(intern, element->obj, element->inf TSRMLS_CC);
                    191:                zend_hash_move_forward_ex(&other->storage, &pos);
                    192:        }
                    193: 
                    194:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    195:        intern->index = 0;
                    196: } /* }}} */
                    197: 
                    198: static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
                    199: {
                    200:        zend_object_value retval;
                    201:        spl_SplObjectStorage *intern;
                    202:        zval *tmp;
                    203: 
                    204:        intern = emalloc(sizeof(spl_SplObjectStorage));
                    205:        memset(intern, 0, sizeof(spl_SplObjectStorage));
                    206:        *obj = intern;
                    207: 
                    208:        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
                    209:        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    210: 
                    211:        zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0);
                    212: 
                    213:        retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_SplOjectStorage_free_storage, NULL TSRMLS_CC);
                    214:        retval.handlers = &spl_handler_SplObjectStorage;
                    215: 
                    216:        if (orig) {
                    217:                spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC);
                    218:                spl_object_storage_addall(intern, other TSRMLS_CC);
                    219:        }
                    220: 
                    221:        return retval;
                    222: }
                    223: /* }}} */
                    224: 
                    225: /* {{{ spl_object_storage_clone */
                    226: static zend_object_value spl_object_storage_clone(zval *zobject TSRMLS_DC)
                    227: {
                    228:        zend_object_value new_obj_val;
                    229:        zend_object *old_object;
                    230:        zend_object *new_object;
                    231:        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
                    232:        spl_SplObjectStorage *intern;
                    233: 
                    234:        old_object = zend_objects_get_address(zobject TSRMLS_CC);
                    235:        new_obj_val = spl_object_storage_new_ex(old_object->ce, &intern, zobject TSRMLS_CC);
                    236:        new_object = &intern->std;
                    237: 
                    238:        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
                    239: 
                    240:        return new_obj_val;
                    241: }
                    242: /* }}} */
                    243: 
                    244: static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
                    245: {
                    246:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
                    247:        spl_SplObjectStorageElement *element;
                    248:        HashTable *props;
                    249:        HashPosition pos;
                    250:        zval *tmp, *storage;
                    251:        char md5str[33];
                    252:        int name_len;
                    253:        char *zname;
                    254: 
                    255:        *is_temp = 0;
                    256: 
                    257:        props = Z_OBJPROP_P(obj);
                    258:        zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
                    259: 
                    260:        if (intern->debug_info == NULL) {
                    261:                ALLOC_HASHTABLE(intern->debug_info);
                    262:                ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0);
                    263:        }
                    264: 
                    265:        if (intern->debug_info->nApplyCount == 0) {
                    266:                zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
                    267: 
                    268:                MAKE_STD_ZVAL(storage);
                    269:                array_init(storage);
                    270: 
                    271:                zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
                    272:                while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
                    273:                                php_spl_object_hash(element->obj, md5str TSRMLS_CC);
                    274:                                MAKE_STD_ZVAL(tmp);
                    275:                                array_init(tmp);
                    276:                                /* Incrementing the refcount of obj and inf would confuse the garbage collector.
                    277:                                 * Prefer to null the destructor */
                    278:                                Z_ARRVAL_P(tmp)->pDestructor = NULL;
                    279:                                add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj);
                    280:                                add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf);
                    281:                                add_assoc_zval_ex(storage, md5str, 33, tmp);
                    282:                                zend_hash_move_forward_ex(&intern->storage, &pos);
                    283:                }
                    284: 
                    285:                zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
                    286:                zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
                    287:                efree(zname);
                    288:        }
                    289: 
                    290:        return intern->debug_info;
                    291: }
                    292: /* }}} */
                    293: 
                    294: /* overriden for garbage collection
                    295:  * This is very hacky, but unfortunately the garbage collector can only query objects for
                    296:  * dependencies through get_properties */
                    297: static HashTable *spl_object_storage_get_properties(zval *obj TSRMLS_DC) /* {{{ */
                    298: {
                    299:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
                    300:        spl_SplObjectStorageElement *element;
                    301:        HashTable *props;
                    302:        HashPosition pos;
                    303:        zval *gcdata_arr = NULL,
                    304:                 **gcdata_arr_pp;
                    305: 
                    306:        props = std_object_handlers.get_properties(obj TSRMLS_CC);
                    307:        
                    308:        if (!GC_G(gc_active)) {
                    309:                zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
                    310:                return props;
                    311:        }
                    312: 
                    313:        if (props->nApplyCount > 0) {
                    314:                return props;
                    315:        }
                    316: 
                    317:        /* clean \x00gcdata, as it may be out of date */
                    318:        if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) {
                    319:                gcdata_arr = *gcdata_arr_pp;
                    320:                zend_hash_clean(Z_ARRVAL_P(gcdata_arr));
                    321:        }
                    322: 
                    323:        if (gcdata_arr == NULL) {
                    324:                MAKE_STD_ZVAL(gcdata_arr);
                    325:                array_init(gcdata_arr);
                    326:                /* don't decrease refcount of members when destroying */
                    327:                Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
                    328: 
                    329:                /* name starts with \x00 to make tampering in user-land more difficult */
                    330:                zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL);
                    331:        }
                    332: 
                    333:        zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
                    334:        while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
                    335:                add_next_index_zval(gcdata_arr, element->obj);
                    336:                add_next_index_zval(gcdata_arr, element->inf);
                    337:                zend_hash_move_forward_ex(&intern->storage, &pos);
                    338:        }
                    339: 
                    340:        return props;
                    341: }
                    342: /* }}} */
                    343: 
                    344: static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */
                    345: {
                    346:        zval result;
                    347: 
                    348:        if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) {
                    349:                return 1;
                    350:        }
                    351: 
                    352:        return Z_LVAL(result);
                    353: }
                    354: /* }}} */
                    355: 
                    356: static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
                    357: {
                    358:        zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC);
                    359:        zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC);
                    360: 
                    361:        if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
                    362:                return 1;
                    363:        }
                    364: 
                    365:        return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC);
                    366: }
                    367: /* }}} */
                    368: 
                    369: /* {{{ spl_array_object_new */
                    370: static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
                    371: {
                    372:        spl_SplObjectStorage *tmp;
                    373:        return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
                    374: }
                    375: /* }}} */
                    376: 
                    377: int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
                    378: {
                    379: #if HAVE_PACKED_OBJECT_VALUE
                    380:        return zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
                    381: #else
                    382:        {
                    383:                zend_object_value zvalue;
                    384:                memset(&zvalue, 0, sizeof(zend_object_value));
                    385:                zvalue.handle = Z_OBJ_HANDLE_P(obj);
                    386:                zvalue.handlers = Z_OBJ_HT_P(obj);
                    387:                return zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
                    388:        }
                    389: #endif
                    390: } /* }}} */
                    391: 
                    392: /* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL)
                    393:  Attaches an object to the storage if not yet contained */
                    394: SPL_METHOD(SplObjectStorage, attach)
                    395: {
                    396:        zval *obj, *inf = NULL;
                    397: 
                    398:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    399: 
                    400:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
                    401:                return;
                    402:        }
                    403:        spl_object_storage_attach(intern, obj, inf TSRMLS_CC);
                    404: } /* }}} */
                    405: 
                    406: /* {{{ proto void SplObjectStorage::detach($obj)
                    407:  Detaches an object from the storage */
                    408: SPL_METHOD(SplObjectStorage, detach)
                    409: {
                    410:        zval *obj;
                    411:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    412: 
                    413:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                    414:                return;
                    415:        }
                    416:        spl_object_storage_detach(intern, obj TSRMLS_CC);
                    417: 
                    418:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    419:        intern->index = 0;
                    420: } /* }}} */
                    421: 
                    422: /* {{{ proto mixed SplObjectStorage::offsetGet($object)
                    423:  Returns associated information for a stored object */
                    424: SPL_METHOD(SplObjectStorage, offsetGet)
                    425: {
                    426:        zval *obj;
                    427:        spl_SplObjectStorageElement *element;
                    428:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    429:        
                    430:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                    431:                return;
                    432:        }
                    433:        element = spl_object_storage_get(intern, obj TSRMLS_CC);
                    434:        if (!element) {
                    435:                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
                    436:        } else {
                    437:                RETURN_ZVAL(element->inf,1, 0);
                    438:        }
                    439: } /* }}} */
                    440: 
                    441: /* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os)
                    442:  Add all elements contained in $os */
                    443: SPL_METHOD(SplObjectStorage, addAll)
                    444: {
                    445:        zval *obj;
                    446:        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
                    447:        spl_SplObjectStorage *other;
                    448: 
                    449:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
                    450:                return;
                    451:        }
                    452: 
                    453:        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
                    454: 
                    455:        spl_object_storage_addall(intern, other TSRMLS_CC);
                    456: 
                    457:        RETURN_LONG(zend_hash_num_elements(&intern->storage));
                    458: } /* }}} */
                    459: 
                    460: /* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os)
                    461:  Remove all elements contained in $os */
                    462: SPL_METHOD(SplObjectStorage, removeAll)
                    463: {
                    464:        zval *obj;
                    465:        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
                    466:        spl_SplObjectStorage *other;
                    467:        spl_SplObjectStorageElement *element;
                    468: 
                    469:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
                    470:                return;
                    471:        }
                    472: 
                    473:        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
                    474: 
                    475:        zend_hash_internal_pointer_reset(&other->storage);
                    476:        while (zend_hash_get_current_data(&other->storage, (void **)&element) == SUCCESS) {
                    477:                if (spl_object_storage_detach(intern, element->obj TSRMLS_CC) == FAILURE) {
                    478:                        zend_hash_move_forward(&other->storage);
                    479:                }
                    480:        }
                    481: 
                    482:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    483:        intern->index = 0;
                    484: 
                    485:        RETURN_LONG(zend_hash_num_elements(&intern->storage));
                    486: } /* }}} */
                    487: 
                    488: /* {{{ proto bool SplObjectStorage::removeAllExcept(SplObjectStorage $os)
                    489:  Remove elements not common to both this SplObjectStorage instance and $os */
                    490: SPL_METHOD(SplObjectStorage, removeAllExcept)
                    491: {
                    492:        zval *obj;
                    493:        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
                    494:        spl_SplObjectStorage *other;
                    495:        spl_SplObjectStorageElement *element;
                    496: 
                    497:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
                    498:                return;
                    499:        }
                    500: 
                    501:        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
                    502: 
                    503:        zend_hash_internal_pointer_reset(&intern->storage);
                    504:        while (zend_hash_get_current_data(&intern->storage, (void **)&element) == SUCCESS) {
                    505:                if (!spl_object_storage_contains(other, element->obj TSRMLS_CC)) {
                    506:                        spl_object_storage_detach(intern, element->obj TSRMLS_CC);
                    507:                }
                    508:                zend_hash_move_forward(&intern->storage);
                    509:        }
                    510: 
                    511:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    512:        intern->index = 0;
                    513: 
                    514:        RETURN_LONG(zend_hash_num_elements(&intern->storage));
                    515: }
                    516: /* }}} */
                    517: 
                    518: /* {{{ proto bool SplObjectStorage::contains($obj)
                    519:  Determine whethe an object is contained in the storage */
                    520: SPL_METHOD(SplObjectStorage, contains)
                    521: {
                    522:        zval *obj;
                    523:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    524: 
                    525:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
                    526:                return;
                    527:        }
                    528:        RETURN_BOOL(spl_object_storage_contains(intern, obj TSRMLS_CC));
                    529: } /* }}} */
                    530: 
                    531: /* {{{ proto int SplObjectStorage::count()
                    532:  Determine number of objects in storage */
                    533: SPL_METHOD(SplObjectStorage, count)
                    534: {
                    535:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    536:        
                    537:        if (zend_parse_parameters_none() == FAILURE) {
                    538:                return;
                    539:        }
                    540:        
                    541:        RETURN_LONG(zend_hash_num_elements(&intern->storage));
                    542: } /* }}} */
                    543: 
                    544: /* {{{ proto void SplObjectStorage::rewind()
                    545:  Rewind to first position */
                    546: SPL_METHOD(SplObjectStorage, rewind)
                    547: {
                    548:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    549:        
                    550:        if (zend_parse_parameters_none() == FAILURE) {
                    551:                return;
                    552:        }
                    553:        
                    554:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    555:        intern->index = 0;
                    556: } /* }}} */
                    557: 
                    558: /* {{{ proto bool SplObjectStorage::valid()
                    559:  Returns whether current position is valid */
                    560: SPL_METHOD(SplObjectStorage, valid)
                    561: {
                    562:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    563:        
                    564:        if (zend_parse_parameters_none() == FAILURE) {
                    565:                return;
                    566:        }
                    567:        
                    568:        RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
                    569: } /* }}} */
                    570: 
                    571: /* {{{ proto mixed SplObjectStorage::key()
                    572:  Returns current key */
                    573: SPL_METHOD(SplObjectStorage, key)
                    574: {
                    575:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    576:        
                    577:        if (zend_parse_parameters_none() == FAILURE) {
                    578:                return;
                    579:        }
                    580:        
                    581:        RETURN_LONG(intern->index);
                    582: } /* }}} */
                    583: 
                    584: /* {{{ proto mixed SplObjectStorage::current()
                    585:  Returns current element */
                    586: SPL_METHOD(SplObjectStorage, current)
                    587: {
                    588:        spl_SplObjectStorageElement *element;
                    589:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    590:        
                    591:        if (zend_parse_parameters_none() == FAILURE) {
                    592:                return;
                    593:        }
                    594:        
                    595:        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
                    596:                return;
                    597:        }
                    598:        RETVAL_ZVAL(element->obj, 1, 0);
                    599: } /* }}} */
                    600: 
                    601: /* {{{ proto mixed SplObjectStorage::getInfo()
                    602:  Returns associated information to current element */
                    603: SPL_METHOD(SplObjectStorage, getInfo)
                    604: {
                    605:        spl_SplObjectStorageElement *element;
                    606:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    607: 
                    608:        if (zend_parse_parameters_none() == FAILURE) {
                    609:                return;
                    610:        }
                    611:        
                    612:        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
                    613:                return;
                    614:        }
                    615:        RETVAL_ZVAL(element->inf, 1, 0);
                    616: } /* }}} */
                    617: 
                    618: /* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf)
                    619:  Sets associated information of current element to $inf */
                    620: SPL_METHOD(SplObjectStorage, setInfo)
                    621: {
                    622:        spl_SplObjectStorageElement *element;
                    623:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    624:        zval *inf;
                    625:        
                    626:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) {
                    627:                return;
                    628:        }
                    629: 
                    630:        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
                    631:                return;
                    632:        }
                    633:        zval_ptr_dtor(&element->inf);
                    634:        element->inf = inf;
                    635:        Z_ADDREF_P(inf);
                    636: } /* }}} */
                    637: 
                    638: /* {{{ proto void SplObjectStorage::next()
                    639:  Moves position forward */
                    640: SPL_METHOD(SplObjectStorage, next)
                    641: {
                    642:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    643:        
                    644:        if (zend_parse_parameters_none() == FAILURE) {
                    645:                return;
                    646:        }
                    647:        
                    648:        zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                    649:        intern->index++;
                    650: } /* }}} */
                    651: 
                    652: /* {{{ proto string SplObjectStorage::serialize()
                    653:  Serializes storage */
                    654: SPL_METHOD(SplObjectStorage, serialize)
                    655: {
                    656:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    657: 
                    658:        spl_SplObjectStorageElement *element;
                    659:        zval members, *pmembers;
                    660:        HashPosition      pos;
                    661:        php_serialize_data_t var_hash;
                    662:        smart_str buf = {0};
                    663: 
                    664:        if (zend_parse_parameters_none() == FAILURE) {
                    665:                return;
                    666:        }
                    667: 
                    668:        PHP_VAR_SERIALIZE_INIT(var_hash);
                    669:        
                    670:        /* storage */
                    671:        smart_str_appendl(&buf, "x:i:", 4);
                    672:        smart_str_append_long(&buf, zend_hash_num_elements(&intern->storage));
                    673:        smart_str_appendc(&buf, ';');
                    674: 
                    675:        zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
                    676: 
                    677:        while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
                    678:                if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) {
                    679:                        smart_str_free(&buf);
                    680:                        PHP_VAR_SERIALIZE_DESTROY(var_hash);
                    681:                        RETURN_NULL();
                    682:                }
                    683:                php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC);
                    684:                smart_str_appendc(&buf, ',');
                    685:                php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC);
                    686:                smart_str_appendc(&buf, ';');
                    687:                zend_hash_move_forward_ex(&intern->storage, &pos);
                    688:        }
                    689: 
                    690:        /* members */
                    691:        smart_str_appendl(&buf, "m:", 2);
                    692:        INIT_PZVAL(&members);
                    693:        Z_ARRVAL(members) = intern->std.properties;
                    694:        Z_TYPE(members) = IS_ARRAY;
                    695:        pmembers = &members;
                    696:        php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
                    697: 
                    698:        /* done */
                    699:        PHP_VAR_SERIALIZE_DESTROY(var_hash);
                    700: 
                    701:        if (buf.c) {
                    702:                RETURN_STRINGL(buf.c, buf.len, 0);
                    703:        } else {
                    704:                RETURN_NULL();
                    705:        }
                    706:        
                    707: } /* }}} */
                    708: 
                    709: /* {{{ proto void SplObjectStorage::unserialize(string serialized)
                    710:  Unserializes storage */
                    711: SPL_METHOD(SplObjectStorage, unserialize)
                    712: {
                    713:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    714: 
                    715:        char *buf;
                    716:        int buf_len;
                    717:        const unsigned char *p, *s;
                    718:        php_unserialize_data_t var_hash;
                    719:        zval *pentry, *pmembers, *pcount = NULL, *pinf;
                    720:        long count;
                    721:        
                    722:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
                    723:                return;
                    724:        }
                    725: 
                    726:        if (buf_len == 0) {
                    727:                zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
                    728:                return;
                    729:        }
                    730: 
                    731:        /* storage */
                    732:        s = p = (const unsigned char*)buf;
                    733:        PHP_VAR_UNSERIALIZE_INIT(var_hash);
                    734: 
                    735:        if (*p!= 'x' || *++p != ':') {
                    736:                goto outexcept;
                    737:        }
                    738:        ++p;
                    739: 
                    740:        ALLOC_INIT_ZVAL(pcount);
                    741:        if (!php_var_unserialize(&pcount, &p, s + buf_len, NULL TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
                    742:                zval_ptr_dtor(&pcount);
                    743:                goto outexcept;
                    744:        }
                    745: 
                    746:        --p; /* for ';' */
                    747:        count = Z_LVAL_P(pcount);
                    748:        zval_ptr_dtor(&pcount);
                    749:                
                    750:        while(count-- > 0) {
                    751:                spl_SplObjectStorageElement *pelement;
                    752:                
                    753:                if (*p != ';') {
                    754:                        goto outexcept;
                    755:                }
                    756:                ++p;
                    757:                if(*p != 'O' && *p != 'C' && *p != 'r') {
                    758:                        goto outexcept;
                    759:                }
                    760:                ALLOC_INIT_ZVAL(pentry);
                    761:                if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
                    762:                        zval_ptr_dtor(&pentry);
                    763:                        goto outexcept;
                    764:                }
                    765:                if(Z_TYPE_P(pentry) != IS_OBJECT) {
                    766:                        zval_ptr_dtor(&pentry);
                    767:                        goto outexcept;
                    768:                }
                    769:                ALLOC_INIT_ZVAL(pinf);
                    770:                if (*p == ',') { /* new version has inf */
                    771:                        ++p;
                    772:                        if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) {
                    773:                                zval_ptr_dtor(&pinf);
                    774:                                goto outexcept;
                    775:                        }
                    776:                }
                    777:                
                    778:                pelement = spl_object_storage_get(intern, pentry TSRMLS_CC);
                    779:                if(pelement) {
                    780:                        if(pelement->inf) {
                    781:                                var_push_dtor(&var_hash, &pelement->inf);
                    782:                        }
                    783:                        if(pelement->obj) {
                    784:                                var_push_dtor(&var_hash, &pelement->obj);
                    785:                        }
                    786:                } 
                    787:                spl_object_storage_attach(intern, pentry, pinf TSRMLS_CC);
                    788:                zval_ptr_dtor(&pentry);
                    789:                zval_ptr_dtor(&pinf);
                    790:        }
                    791: 
                    792:        if (*p != ';') {
                    793:                goto outexcept;
                    794:        }
                    795:        ++p;
                    796: 
                    797:        /* members */
                    798:        if (*p!= 'm' || *++p != ':') {
                    799:                goto outexcept;
                    800:        }
                    801:        ++p;
                    802: 
                    803:        ALLOC_INIT_ZVAL(pmembers);
                    804:        if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
                    805:                zval_ptr_dtor(&pmembers);
                    806:                goto outexcept;
                    807:        }
                    808: 
                    809:        /* copy members */
                    810:        zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
                    811:        zval_ptr_dtor(&pmembers);
                    812: 
                    813:        /* done reading $serialized */
                    814: 
                    815:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                    816:        return;
                    817: 
                    818: outexcept:
                    819:        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                    820:        zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
                    821:        return;
                    822: 
                    823: } /* }}} */
                    824: 
                    825: ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
                    826:        ZEND_ARG_INFO(0, object)
                    827: ZEND_END_ARG_INFO();
                    828: 
                    829: ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1)
                    830:        ZEND_ARG_INFO(0, object)
                    831:        ZEND_ARG_INFO(0, inf)
                    832: ZEND_END_ARG_INFO();
                    833: 
                    834: ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
                    835:        ZEND_ARG_INFO(0, serialized)
                    836: ZEND_END_ARG_INFO();
                    837: 
                    838: ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
                    839:        ZEND_ARG_INFO(0, info)
                    840: ZEND_END_ARG_INFO();
                    841: 
                    842: ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
                    843:        ZEND_ARG_INFO(0, object)
                    844: ZEND_END_ARG_INFO()
                    845: 
                    846: ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0)
                    847: ZEND_END_ARG_INFO()
                    848: 
                    849: static const zend_function_entry spl_funcs_SplObjectStorage[] = {
                    850:        SPL_ME(SplObjectStorage,  attach,      arginfo_attach,        0)
                    851:        SPL_ME(SplObjectStorage,  detach,      arginfo_Object,        0)
                    852:        SPL_ME(SplObjectStorage,  contains,    arginfo_Object,        0)
                    853:        SPL_ME(SplObjectStorage,  addAll,      arginfo_Object,        0)
                    854:        SPL_ME(SplObjectStorage,  removeAll,   arginfo_Object,        0)
                    855:        SPL_ME(SplObjectStorage,  removeAllExcept, arginfo_Object,    0)
                    856:        SPL_ME(SplObjectStorage,  getInfo,     arginfo_splobject_void,0)
                    857:        SPL_ME(SplObjectStorage,  setInfo,     arginfo_setInfo,       0)
                    858:        /* Countable */
                    859:        SPL_ME(SplObjectStorage,  count,       arginfo_splobject_void,0)
                    860:        /* Iterator */
                    861:        SPL_ME(SplObjectStorage,  rewind,      arginfo_splobject_void,0)
                    862:        SPL_ME(SplObjectStorage,  valid,       arginfo_splobject_void,0)
                    863:        SPL_ME(SplObjectStorage,  key,         arginfo_splobject_void,0)
                    864:        SPL_ME(SplObjectStorage,  current,     arginfo_splobject_void,0)
                    865:        SPL_ME(SplObjectStorage,  next,        arginfo_splobject_void,0)
                    866:        /* Serializable */
                    867:        SPL_ME(SplObjectStorage,  unserialize, arginfo_Serialized,    0)
                    868:        SPL_ME(SplObjectStorage,  serialize,   arginfo_splobject_void,0)
                    869:        /* ArrayAccess */
                    870:        SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0)
                    871:        SPL_MA(SplObjectStorage, offsetSet,    SplObjectStorage, attach,   arginfo_attach, 0)
                    872:        SPL_MA(SplObjectStorage, offsetUnset,  SplObjectStorage, detach,   arginfo_offsetGet, 0)
                    873:        SPL_ME(SplObjectStorage, offsetGet,    arginfo_offsetGet,     0)
                    874:        {NULL, NULL, NULL}
                    875: };
                    876: 
                    877: typedef enum {
                    878:        MIT_NEED_ANY     = 0,
                    879:        MIT_NEED_ALL     = 1,
                    880:        MIT_KEYS_NUMERIC = 0,
                    881:        MIT_KEYS_ASSOC   = 2
                    882: } MultipleIteratorFlags;
                    883: 
                    884: #define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT   1
                    885: #define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY       2
                    886: 
                    887: /* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC])
                    888:    Iterator that iterates over several iterators one after the other */
                    889: SPL_METHOD(MultipleIterator, __construct)
                    890: {
                    891:        spl_SplObjectStorage   *intern;
                    892:        long                    flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
                    893:        zend_error_handling error_handling;
                    894: 
                    895:        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
                    896: 
                    897:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
                    898:                zend_restore_error_handling(&error_handling TSRMLS_CC);
                    899:                return;
                    900:        }
                    901: 
                    902:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    903:        intern->flags = flags;
                    904:        zend_restore_error_handling(&error_handling TSRMLS_CC);
                    905: }
                    906: /* }}} */
                    907: 
                    908: /* {{{ proto int MultipleIterator::getFlags()
                    909:    Return current flags */
                    910: SPL_METHOD(MultipleIterator, getFlags)
                    911: {
                    912:        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    913:        
                    914:        if (zend_parse_parameters_none() == FAILURE) {
                    915:                return;
                    916:        }
                    917:        RETURN_LONG(intern->flags);
                    918: }
                    919: /* }}} */
                    920: 
                    921: /* {{{ proto int MultipleIterator::setFlags(int flags)
                    922:    Set flags */
                    923: SPL_METHOD(MultipleIterator, setFlags)
                    924: {
                    925:        spl_SplObjectStorage *intern;
                    926:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    927: 
                    928:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
                    929:                return;
                    930:        }
                    931: }
                    932: /* }}} */
                    933: 
                    934: /* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException
                    935:    Attach a new iterator */
                    936: SPL_METHOD(MultipleIterator, attachIterator)
                    937: {
                    938:        spl_SplObjectStorage        *intern;
                    939:        zval                        *iterator = NULL, *info = NULL;
                    940: 
                    941:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
                    942:                return;
                    943:        }
                    944: 
                    945:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    946: 
                    947:        if (info != NULL) {
                    948:                spl_SplObjectStorageElement *element;
                    949:                zval                         compare_result;
                    950: 
                    951:                if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING) {
                    952:                        zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
                    953:                        return;
                    954:                }
                    955: 
                    956:                zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    957:                while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
                    958:                        is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
                    959:                        if (Z_LVAL(compare_result)) {
                    960:                                zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
                    961:                                return;
                    962:                        }
                    963:                        zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                    964:                }
                    965:        }
                    966: 
                    967:        spl_object_storage_attach(intern, iterator, info TSRMLS_CC);
                    968: }
                    969: /* }}} */
                    970: 
                    971: /* {{{ proto void MultipleIterator::rewind()
                    972:    Rewind all attached iterator instances */
                    973: SPL_METHOD(MultipleIterator, rewind)
                    974: {
                    975:        spl_SplObjectStorage        *intern;
                    976:        spl_SplObjectStorageElement *element;
                    977:        zval                        *it;
                    978: 
                    979:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                    980:        
                    981:        if (zend_parse_parameters_none() == FAILURE) {
                    982:                return;
                    983:        }
                    984: 
                    985:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                    986:        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
                    987:                it = element->obj;
                    988:                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
                    989:                zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                    990:        }
                    991: }
                    992: /* }}} */
                    993: 
                    994: /* {{{ proto void MultipleIterator::next()
                    995:    Move all attached iterator instances forward */
                    996: SPL_METHOD(MultipleIterator, next)
                    997: {
                    998:        spl_SplObjectStorage        *intern;
                    999:        spl_SplObjectStorageElement *element;
                   1000:        zval                        *it;
                   1001: 
                   1002:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1003:        
                   1004:        if (zend_parse_parameters_none() == FAILURE) {
                   1005:                return;
                   1006:        }
                   1007: 
                   1008:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                   1009:        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
                   1010:                it = element->obj;
                   1011:                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
                   1012:                zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                   1013:        }
                   1014: }
                   1015: /* }}} */
                   1016: 
                   1017: /* {{{ proto bool MultipleIterator::valid()
                   1018:    Return whether all or one sub iterator is valid depending on flags */
                   1019: SPL_METHOD(MultipleIterator, valid)
                   1020: {
                   1021:        spl_SplObjectStorage        *intern;
                   1022:        spl_SplObjectStorageElement *element;
                   1023:        zval                        *it, *retval = NULL;
                   1024:        long                         expect, valid;
                   1025: 
                   1026:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1027:        
                   1028:        if (zend_parse_parameters_none() == FAILURE) {
                   1029:                return;
                   1030:        }
                   1031: 
                   1032:        if (!zend_hash_num_elements(&intern->storage)) {
                   1033:                RETURN_FALSE;
                   1034:        }
                   1035: 
                   1036:        expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
                   1037: 
                   1038:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                   1039:        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
                   1040:                it = element->obj;
                   1041:                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
                   1042: 
                   1043:                if (retval) {
                   1044:                        valid = Z_LVAL_P(retval);
                   1045:                        zval_ptr_dtor(&retval);
                   1046:                } else {
                   1047:                        valid = 0;
                   1048:                }
                   1049: 
                   1050:                if (expect != valid) {
                   1051:                        RETURN_BOOL(!expect);
                   1052:                }
                   1053: 
                   1054:                zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                   1055:        }
                   1056: 
                   1057:        RETURN_BOOL(expect);
                   1058: }
                   1059: /* }}} */
                   1060: 
                   1061: static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
                   1062: {
                   1063:        spl_SplObjectStorageElement *element;
                   1064:        zval                        *it, *retval = NULL;
                   1065:        int                          valid = 1, num_elements;
                   1066: 
                   1067:        num_elements = zend_hash_num_elements(&intern->storage);
                   1068:        if (num_elements < 1) {
                   1069:                RETURN_FALSE;
                   1070:        }
                   1071: 
                   1072:        array_init_size(return_value, num_elements);
                   1073:        
                   1074:        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
                   1075:        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
                   1076:                it = element->obj;
                   1077:                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
                   1078: 
                   1079:                if (retval) {
                   1080:                        valid = Z_LVAL_P(retval);
                   1081:                        zval_ptr_dtor(&retval);
                   1082:                } else {
                   1083:                        valid = 0;
                   1084:                }
                   1085: 
                   1086:                if (valid) {
                   1087:                        if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
                   1088:                                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
                   1089:                        } else {
                   1090:                                zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key,     "key",     &retval);
                   1091:                        }
                   1092:                        if (!retval) {
                   1093:                                zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
                   1094:                                return;
                   1095:                        }
                   1096:                } else if (intern->flags & MIT_NEED_ALL) {
                   1097:                        if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
                   1098:                                zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
                   1099:                        } else {
                   1100:                                zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
                   1101:                        }
                   1102:                        return;
                   1103:                } else {
                   1104:                        ALLOC_INIT_ZVAL(retval);
                   1105:                }
                   1106: 
                   1107:                if (intern->flags & MIT_KEYS_ASSOC) {
                   1108:                        switch (Z_TYPE_P(element->inf)) {
                   1109:                                case IS_LONG:
                   1110:                                        add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
                   1111:                                        break;
                   1112:                                case IS_STRING:
                   1113:                                        add_assoc_zval_ex(return_value, Z_STRVAL_P(element->inf), Z_STRLEN_P(element->inf)+1U, retval);
                   1114:                                        break;
                   1115:                                default:
                   1116:                                        zval_ptr_dtor(&retval);
                   1117:                                        zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
                   1118:                                        return;
                   1119:                        }
                   1120:                } else {
                   1121:                        add_next_index_zval(return_value, retval);
                   1122:                }
                   1123: 
                   1124:                zend_hash_move_forward_ex(&intern->storage, &intern->pos);
                   1125:        }
                   1126: }
                   1127: /* }}} */
                   1128: 
                   1129: /* {{{ proto array current() throws RuntimeException throws InvalidArgumentException
                   1130:    Return an array of all registered Iterator instances current() result */
                   1131: SPL_METHOD(MultipleIterator, current)
                   1132: {
                   1133:        spl_SplObjectStorage        *intern;
                   1134:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1135:        
                   1136:        if (zend_parse_parameters_none() == FAILURE) {
                   1137:                return;
                   1138:        }
                   1139: 
                   1140:        spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
                   1141: }
                   1142: /* }}} */
                   1143: 
                   1144: /* {{{ proto array MultipleIterator::key()
                   1145:    Return an array of all registered Iterator instances key() result */
                   1146: SPL_METHOD(MultipleIterator, key)
                   1147: {
                   1148:        spl_SplObjectStorage        *intern;
                   1149:        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
                   1150:        
                   1151:        if (zend_parse_parameters_none() == FAILURE) {
                   1152:                return;
                   1153:        }
                   1154: 
                   1155:        spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
                   1156: }
                   1157: /* }}} */
                   1158: 
                   1159: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
                   1160:        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
                   1161:        ZEND_ARG_INFO(0, infos)
                   1162: ZEND_END_ARG_INFO();
                   1163: 
                   1164: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
                   1165:        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
                   1166: ZEND_END_ARG_INFO();
                   1167: 
                   1168: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
                   1169:        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
                   1170: ZEND_END_ARG_INFO();
                   1171: 
                   1172: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1)
                   1173:        ZEND_ARG_INFO(0, flags)
                   1174: ZEND_END_ARG_INFO();
                   1175: 
                   1176: static const zend_function_entry spl_funcs_MultipleIterator[] = {
                   1177:        SPL_ME(MultipleIterator,  __construct,            arginfo_MultipleIterator_setflags,          0)
                   1178:        SPL_ME(MultipleIterator,  getFlags,               arginfo_splobject_void,                     0)
                   1179:        SPL_ME(MultipleIterator,  setFlags,               arginfo_MultipleIterator_setflags,          0)
                   1180:        SPL_ME(MultipleIterator,  attachIterator,         arginfo_MultipleIterator_attachIterator,    0)
                   1181:        SPL_MA(MultipleIterator,  detachIterator,         SplObjectStorage, detach,   arginfo_MultipleIterator_detachIterator,   0)
                   1182:        SPL_MA(MultipleIterator,  containsIterator,       SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
                   1183:        SPL_MA(MultipleIterator,  countIterators,         SplObjectStorage, count,    arginfo_splobject_void,                    0)
                   1184:        /* Iterator */
                   1185:        SPL_ME(MultipleIterator,  rewind,                 arginfo_splobject_void,                     0)
                   1186:        SPL_ME(MultipleIterator,  valid,                  arginfo_splobject_void,                     0)
                   1187:        SPL_ME(MultipleIterator,  key,                    arginfo_splobject_void,                     0)
                   1188:        SPL_ME(MultipleIterator,  current,                arginfo_splobject_void,                     0)
                   1189:        SPL_ME(MultipleIterator,  next,                   arginfo_splobject_void,                     0)
                   1190:        {NULL, NULL, NULL}
                   1191: };
                   1192: 
                   1193: /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
                   1194: PHP_MINIT_FUNCTION(spl_observer)
                   1195: {
                   1196:        REGISTER_SPL_INTERFACE(SplObserver);
                   1197:        REGISTER_SPL_INTERFACE(SplSubject);
                   1198: 
                   1199:        REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
                   1200:        memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
                   1201: 
                   1202:        spl_handler_SplObjectStorage.get_properties  = spl_object_storage_get_properties;
                   1203:        spl_handler_SplObjectStorage.get_debug_info  = spl_object_storage_debug_info;
                   1204:        spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects;
                   1205:        spl_handler_SplObjectStorage.clone_obj       = spl_object_storage_clone;
                   1206: 
                   1207:        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
                   1208:        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
                   1209:        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
                   1210:        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
                   1211: 
                   1212:        REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
                   1213:        REGISTER_SPL_ITERATOR(MultipleIterator);
                   1214: 
                   1215:        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY",     MIT_NEED_ANY);
                   1216:        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL",     MIT_NEED_ALL);
                   1217:        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
                   1218:        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC",   MIT_KEYS_ASSOC);
                   1219: 
                   1220:        return SUCCESS;
                   1221: }
                   1222: /* }}} */
                   1223: 
                   1224: /*
                   1225:  * Local variables:
                   1226:  * tab-width: 4
                   1227:  * c-basic-offset: 4
                   1228:  * End:
                   1229:  * vim600: fdm=marker
                   1230:  * vim: noet sw=4 ts=4
                   1231:  */

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