Annotation of embedaddon/php/ext/spl/spl_observer.c, revision 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>