Back to index

php5  5.3.10
spl_observer.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is SplSubject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Marcus Boerger <helly@php.net>                              |
00016    |          Etienne Kneuss <colder@php.net>                             |
00017    +----------------------------------------------------------------------+
00018  */
00019 
00020 /* $Id: spl_observer.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #ifdef HAVE_CONFIG_H
00023 # include "config.h"
00024 #endif
00025 
00026 #include "php.h"
00027 #include "php_ini.h"
00028 #include "ext/standard/info.h"
00029 #include "ext/standard/php_var.h"
00030 #include "ext/standard/php_smart_str.h"
00031 #include "zend_interfaces.h"
00032 #include "zend_exceptions.h"
00033 
00034 #include "php_spl.h"
00035 #include "spl_functions.h"
00036 #include "spl_engine.h"
00037 #include "spl_observer.h"
00038 #include "spl_iterators.h"
00039 #include "spl_array.h"
00040 #include "spl_exceptions.h"
00041 
00042 SPL_METHOD(SplObserver, update);
00043 SPL_METHOD(SplSubject, attach);
00044 SPL_METHOD(SplSubject, detach);
00045 SPL_METHOD(SplSubject, notify);
00046 
00047 ZEND_BEGIN_ARG_INFO(arginfo_SplObserver_update, 0)
00048        ZEND_ARG_OBJ_INFO(0, SplSubject, SplSubject, 0)
00049 ZEND_END_ARG_INFO();
00050 
00051 static const zend_function_entry spl_funcs_SplObserver[] = {
00052        SPL_ABSTRACT_ME(SplObserver, update,   arginfo_SplObserver_update)
00053        {NULL, NULL, NULL}
00054 };
00055 
00056 ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_attach, 0)
00057        ZEND_ARG_OBJ_INFO(0, SplObserver, SplObserver, 0)
00058 ZEND_END_ARG_INFO();
00059 
00060 ZEND_BEGIN_ARG_INFO(arginfo_SplSubject_void, 0)
00061 ZEND_END_ARG_INFO();
00062 
00063 /*ZEND_BEGIN_ARG_INFO_EX(arginfo_SplSubject_notify, 0, 0, 1)
00064        ZEND_ARG_OBJ_INFO(0, ignore, SplObserver, 1)
00065 ZEND_END_ARG_INFO();*/
00066 
00067 static const zend_function_entry spl_funcs_SplSubject[] = {
00068        SPL_ABSTRACT_ME(SplSubject,  attach,   arginfo_SplSubject_attach)
00069        SPL_ABSTRACT_ME(SplSubject,  detach,   arginfo_SplSubject_attach)
00070        SPL_ABSTRACT_ME(SplSubject,  notify,   arginfo_SplSubject_void)
00071        {NULL, NULL, NULL}
00072 };
00073 
00074 PHPAPI zend_class_entry     *spl_ce_SplObserver;
00075 PHPAPI zend_class_entry     *spl_ce_SplSubject;
00076 PHPAPI zend_class_entry     *spl_ce_SplObjectStorage;
00077 PHPAPI zend_class_entry     *spl_ce_MultipleIterator;
00078 
00079 PHPAPI zend_object_handlers spl_handler_SplObjectStorage;
00080 
00081 typedef struct _spl_SplObjectStorage { /* {{{ */
00082        zend_object       std;
00083        HashTable         storage;
00084        long              index;
00085        HashPosition      pos;
00086        long              flags;
00087        HashTable        *debug_info;
00088 } spl_SplObjectStorage; /* }}} */
00089 
00090 /* {{{ storage is an assoc aray of [zend_object_value]=>[zval *obj, zval *inf] */
00091 typedef struct _spl_SplObjectStorageElement {
00092        zval* obj;
00093        zval* inf;
00094 } spl_SplObjectStorageElement; /* }}} */
00095 
00096 void spl_SplOjectStorage_free_storage(void *object TSRMLS_DC) /* {{{ */
00097 {
00098        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)object;
00099 
00100        zend_object_std_dtor(&intern->std TSRMLS_CC);
00101        
00102        zend_hash_destroy(&intern->storage);
00103        
00104        if (intern->debug_info != NULL) {
00105               zend_hash_destroy(intern->debug_info);
00106               efree(intern->debug_info);
00107        }
00108 
00109        efree(object);
00110 } /* }}} */
00111 
00112 static void spl_object_storage_dtor(spl_SplObjectStorageElement *element) /* {{{ */
00113 {
00114        zval_ptr_dtor(&element->obj);
00115        zval_ptr_dtor(&element->inf);
00116 } /* }}} */
00117 
00118 
00119 spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
00120 {
00121        spl_SplObjectStorageElement *element;
00122        zend_object_value *pzvalue; 
00123 #if HAVE_PACKED_OBJECT_VALUE
00124        pzvalue = &Z_OBJVAL_P(obj);
00125 #else
00126        zend_object_value zvalue;
00127        memset(&zvalue, 0, sizeof(zend_object_value));
00128        zvalue.handle = Z_OBJ_HANDLE_P(obj);
00129        zvalue.handlers = Z_OBJ_HT_P(obj);
00130        pzvalue = &zvalue;
00131 #endif
00132        if (zend_hash_find(&intern->storage, (char*)pzvalue, sizeof(zend_object_value), (void**)&element) == SUCCESS) {
00133               return element;
00134        } else {
00135               return NULL;
00136        }
00137 } /* }}} */
00138 
00139 void spl_object_storage_attach(spl_SplObjectStorage *intern, zval *obj, zval *inf TSRMLS_DC) /* {{{ */
00140 {
00141        spl_SplObjectStorageElement *pelement, element;
00142        pelement = spl_object_storage_get(intern, obj TSRMLS_CC);
00143        if (inf) {
00144               Z_ADDREF_P(inf);
00145        } else {
00146               ALLOC_INIT_ZVAL(inf);
00147        }
00148        if (pelement) {
00149               zval_ptr_dtor(&pelement->inf);
00150               pelement->inf = inf;
00151               return;
00152        }
00153        Z_ADDREF_P(obj);
00154        element.obj = obj;
00155        element.inf = inf;
00156 #if HAVE_PACKED_OBJECT_VALUE
00157        zend_hash_update(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);       
00158 #else
00159        {
00160               zend_object_value zvalue;
00161               memset(&zvalue, 0, sizeof(zend_object_value));
00162               zvalue.handle = Z_OBJ_HANDLE_P(obj);
00163               zvalue.handlers = Z_OBJ_HT_P(obj);
00164               zend_hash_update(&intern->storage, (char*)&zvalue, sizeof(zend_object_value), &element, sizeof(spl_SplObjectStorageElement), NULL);
00165        }
00166 #endif
00167 } /* }}} */
00168 
00169 int spl_object_storage_detach(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
00170 {
00171 #if HAVE_PACKED_OBJECT_VALUE
00172        return zend_hash_del(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
00173 #else
00174        {
00175               zend_object_value zvalue;
00176               memset(&zvalue, 0, sizeof(zend_object_value));
00177               zvalue.handle = Z_OBJ_HANDLE_P(obj);
00178               zvalue.handlers = Z_OBJ_HT_P(obj);
00179               return zend_hash_del(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
00180        }
00181 #endif
00182 } /* }}}*/
00183 
00184 void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other TSRMLS_DC) { /* {{{ */
00185        HashPosition pos;
00186        spl_SplObjectStorageElement *element;
00187 
00188        zend_hash_internal_pointer_reset_ex(&other->storage, &pos);
00189        while (zend_hash_get_current_data_ex(&other->storage, (void **)&element, &pos) == SUCCESS) {
00190               spl_object_storage_attach(intern, element->obj, element->inf TSRMLS_CC);
00191               zend_hash_move_forward_ex(&other->storage, &pos);
00192        }
00193 
00194        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00195        intern->index = 0;
00196 } /* }}} */
00197 
00198 static zend_object_value spl_object_storage_new_ex(zend_class_entry *class_type, spl_SplObjectStorage **obj, zval *orig TSRMLS_DC) /* {{{ */
00199 {
00200        zend_object_value retval;
00201        spl_SplObjectStorage *intern;
00202        zval *tmp;
00203 
00204        intern = emalloc(sizeof(spl_SplObjectStorage));
00205        memset(intern, 0, sizeof(spl_SplObjectStorage));
00206        *obj = intern;
00207 
00208        zend_object_std_init(&intern->std, class_type TSRMLS_CC);
00209        zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00210 
00211        zend_hash_init(&intern->storage, 0, NULL, (void (*)(void *))spl_object_storage_dtor, 0);
00212 
00213        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);
00214        retval.handlers = &spl_handler_SplObjectStorage;
00215 
00216        if (orig) {
00217               spl_SplObjectStorage *other = (spl_SplObjectStorage*)zend_object_store_get_object(orig TSRMLS_CC);
00218               spl_object_storage_addall(intern, other TSRMLS_CC);
00219        }
00220 
00221        return retval;
00222 }
00223 /* }}} */
00224 
00225 /* {{{ spl_object_storage_clone */
00226 static zend_object_value spl_object_storage_clone(zval *zobject TSRMLS_DC)
00227 {
00228        zend_object_value new_obj_val;
00229        zend_object *old_object;
00230        zend_object *new_object;
00231        zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
00232        spl_SplObjectStorage *intern;
00233 
00234        old_object = zend_objects_get_address(zobject TSRMLS_CC);
00235        new_obj_val = spl_object_storage_new_ex(old_object->ce, &intern, zobject TSRMLS_CC);
00236        new_object = &intern->std;
00237 
00238        zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
00239 
00240        return new_obj_val;
00241 }
00242 /* }}} */
00243 
00244 static HashTable* spl_object_storage_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
00245 {
00246        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
00247        spl_SplObjectStorageElement *element;
00248        HashTable *props;
00249        HashPosition pos;
00250        zval *tmp, *storage;
00251        char md5str[33];
00252        int name_len;
00253        char *zname;
00254 
00255        *is_temp = 0;
00256 
00257        props = Z_OBJPROP_P(obj);
00258        zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
00259 
00260        if (intern->debug_info == NULL) {
00261               ALLOC_HASHTABLE(intern->debug_info);
00262               ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(props) + 1, 0);
00263        }
00264 
00265        if (intern->debug_info->nApplyCount == 0) {
00266               zend_hash_copy(intern->debug_info, props, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
00267 
00268               MAKE_STD_ZVAL(storage);
00269               array_init(storage);
00270 
00271               zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
00272               while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
00273                             php_spl_object_hash(element->obj, md5str TSRMLS_CC);
00274                             MAKE_STD_ZVAL(tmp);
00275                             array_init(tmp);
00276                             /* Incrementing the refcount of obj and inf would confuse the garbage collector.
00277                              * Prefer to null the destructor */
00278                             Z_ARRVAL_P(tmp)->pDestructor = NULL;
00279                             add_assoc_zval_ex(tmp, "obj", sizeof("obj"), element->obj);
00280                             add_assoc_zval_ex(tmp, "inf", sizeof("inf"), element->inf);
00281                             add_assoc_zval_ex(storage, md5str, 33, tmp);
00282                             zend_hash_move_forward_ex(&intern->storage, &pos);
00283               }
00284 
00285               zname = spl_gen_private_prop_name(spl_ce_SplObjectStorage, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
00286               zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
00287               efree(zname);
00288        }
00289 
00290        return intern->debug_info;
00291 }
00292 /* }}} */
00293 
00294 /* overriden for garbage collection
00295  * This is very hacky, but unfortunately the garbage collector can only query objects for
00296  * dependencies through get_properties */
00297 static HashTable *spl_object_storage_get_properties(zval *obj TSRMLS_DC) /* {{{ */
00298 {
00299        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
00300        spl_SplObjectStorageElement *element;
00301        HashTable *props;
00302        HashPosition pos;
00303        zval *gcdata_arr = NULL,
00304                **gcdata_arr_pp;
00305 
00306        props = std_object_handlers.get_properties(obj TSRMLS_CC);
00307        
00308        if (!GC_G(gc_active)) {
00309               zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
00310               return props;
00311        }
00312 
00313        if (props->nApplyCount > 0) {
00314               return props;
00315        }
00316 
00317        /* clean \x00gcdata, as it may be out of date */
00318        if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) {
00319               gcdata_arr = *gcdata_arr_pp;
00320               zend_hash_clean(Z_ARRVAL_P(gcdata_arr));
00321        }
00322 
00323        if (gcdata_arr == NULL) {
00324               MAKE_STD_ZVAL(gcdata_arr);
00325               array_init(gcdata_arr);
00326               /* don't decrease refcount of members when destroying */
00327               Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
00328 
00329               /* name starts with \x00 to make tampering in user-land more difficult */
00330               zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL);
00331        }
00332 
00333        zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
00334        while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
00335               add_next_index_zval(gcdata_arr, element->obj);
00336               add_next_index_zval(gcdata_arr, element->inf);
00337               zend_hash_move_forward_ex(&intern->storage, &pos);
00338        }
00339 
00340        return props;
00341 }
00342 /* }}} */
00343 
00344 static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */
00345 {
00346        zval result;
00347 
00348        if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) {
00349               return 1;
00350        }
00351 
00352        return Z_LVAL(result);
00353 }
00354 /* }}} */
00355 
00356 static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
00357 {
00358        zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC);
00359        zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC);
00360 
00361        if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
00362               return 1;
00363        }
00364 
00365        return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC);
00366 }
00367 /* }}} */
00368 
00369 /* {{{ spl_array_object_new */
00370 static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
00371 {
00372        spl_SplObjectStorage *tmp;
00373        return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
00374 }
00375 /* }}} */
00376 
00377 int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */
00378 {
00379 #if HAVE_PACKED_OBJECT_VALUE
00380        return zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value));
00381 #else
00382        {
00383               zend_object_value zvalue;
00384               memset(&zvalue, 0, sizeof(zend_object_value));
00385               zvalue.handle = Z_OBJ_HANDLE_P(obj);
00386               zvalue.handlers = Z_OBJ_HT_P(obj);
00387               return zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value));
00388        }
00389 #endif
00390 } /* }}} */
00391 
00392 /* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL)
00393  Attaches an object to the storage if not yet contained */
00394 SPL_METHOD(SplObjectStorage, attach)
00395 {
00396        zval *obj, *inf = NULL;
00397 
00398        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00399 
00400        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
00401               return;
00402        }
00403        spl_object_storage_attach(intern, obj, inf TSRMLS_CC);
00404 } /* }}} */
00405 
00406 /* {{{ proto void SplObjectStorage::detach($obj)
00407  Detaches an object from the storage */
00408 SPL_METHOD(SplObjectStorage, detach)
00409 {
00410        zval *obj;
00411        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00412 
00413        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
00414               return;
00415        }
00416        spl_object_storage_detach(intern, obj TSRMLS_CC);
00417 
00418        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00419        intern->index = 0;
00420 } /* }}} */
00421 
00422 /* {{{ proto mixed SplObjectStorage::offsetGet($object)
00423  Returns associated information for a stored object */
00424 SPL_METHOD(SplObjectStorage, offsetGet)
00425 {
00426        zval *obj;
00427        spl_SplObjectStorageElement *element;
00428        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00429        
00430        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
00431               return;
00432        }
00433        element = spl_object_storage_get(intern, obj TSRMLS_CC);
00434        if (!element) {
00435               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
00436        } else {
00437               RETURN_ZVAL(element->inf,1, 0);
00438        }
00439 } /* }}} */
00440 
00441 /* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os)
00442  Add all elements contained in $os */
00443 SPL_METHOD(SplObjectStorage, addAll)
00444 {
00445        zval *obj;
00446        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
00447        spl_SplObjectStorage *other;
00448 
00449        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
00450               return;
00451        }
00452 
00453        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
00454 
00455        spl_object_storage_addall(intern, other TSRMLS_CC);
00456 
00457        RETURN_LONG(zend_hash_num_elements(&intern->storage));
00458 } /* }}} */
00459 
00460 /* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os)
00461  Remove all elements contained in $os */
00462 SPL_METHOD(SplObjectStorage, removeAll)
00463 {
00464        zval *obj;
00465        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
00466        spl_SplObjectStorage *other;
00467        spl_SplObjectStorageElement *element;
00468 
00469        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
00470               return;
00471        }
00472 
00473        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
00474 
00475        zend_hash_internal_pointer_reset(&other->storage);
00476        while (zend_hash_get_current_data(&other->storage, (void **)&element) == SUCCESS) {
00477               if (spl_object_storage_detach(intern, element->obj TSRMLS_CC) == FAILURE) {
00478                      zend_hash_move_forward(&other->storage);
00479               }
00480        }
00481 
00482        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00483        intern->index = 0;
00484 
00485        RETURN_LONG(zend_hash_num_elements(&intern->storage));
00486 } /* }}} */
00487 
00488 /* {{{ proto bool SplObjectStorage::removeAllExcept(SplObjectStorage $os)
00489  Remove elements not common to both this SplObjectStorage instance and $os */
00490 SPL_METHOD(SplObjectStorage, removeAllExcept)
00491 {
00492        zval *obj;
00493        spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
00494        spl_SplObjectStorage *other;
00495        spl_SplObjectStorageElement *element;
00496 
00497        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
00498               return;
00499        }
00500 
00501        other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
00502 
00503        zend_hash_internal_pointer_reset(&intern->storage);
00504        while (zend_hash_get_current_data(&intern->storage, (void **)&element) == SUCCESS) {
00505               if (!spl_object_storage_contains(other, element->obj TSRMLS_CC)) {
00506                      spl_object_storage_detach(intern, element->obj TSRMLS_CC);
00507               }
00508               zend_hash_move_forward(&intern->storage);
00509        }
00510 
00511        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00512        intern->index = 0;
00513 
00514        RETURN_LONG(zend_hash_num_elements(&intern->storage));
00515 }
00516 /* }}} */
00517 
00518 /* {{{ proto bool SplObjectStorage::contains($obj)
00519  Determine whethe an object is contained in the storage */
00520 SPL_METHOD(SplObjectStorage, contains)
00521 {
00522        zval *obj;
00523        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00524 
00525        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
00526               return;
00527        }
00528        RETURN_BOOL(spl_object_storage_contains(intern, obj TSRMLS_CC));
00529 } /* }}} */
00530 
00531 /* {{{ proto int SplObjectStorage::count()
00532  Determine number of objects in storage */
00533 SPL_METHOD(SplObjectStorage, count)
00534 {
00535        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00536        
00537        if (zend_parse_parameters_none() == FAILURE) {
00538               return;
00539        }
00540        
00541        RETURN_LONG(zend_hash_num_elements(&intern->storage));
00542 } /* }}} */
00543 
00544 /* {{{ proto void SplObjectStorage::rewind()
00545  Rewind to first position */
00546 SPL_METHOD(SplObjectStorage, rewind)
00547 {
00548        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00549        
00550        if (zend_parse_parameters_none() == FAILURE) {
00551               return;
00552        }
00553        
00554        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00555        intern->index = 0;
00556 } /* }}} */
00557 
00558 /* {{{ proto bool SplObjectStorage::valid()
00559  Returns whether current position is valid */
00560 SPL_METHOD(SplObjectStorage, valid)
00561 {
00562        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00563        
00564        if (zend_parse_parameters_none() == FAILURE) {
00565               return;
00566        }
00567        
00568        RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
00569 } /* }}} */
00570 
00571 /* {{{ proto mixed SplObjectStorage::key()
00572  Returns current key */
00573 SPL_METHOD(SplObjectStorage, key)
00574 {
00575        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00576        
00577        if (zend_parse_parameters_none() == FAILURE) {
00578               return;
00579        }
00580        
00581        RETURN_LONG(intern->index);
00582 } /* }}} */
00583 
00584 /* {{{ proto mixed SplObjectStorage::current()
00585  Returns current element */
00586 SPL_METHOD(SplObjectStorage, current)
00587 {
00588        spl_SplObjectStorageElement *element;
00589        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00590        
00591        if (zend_parse_parameters_none() == FAILURE) {
00592               return;
00593        }
00594        
00595        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
00596               return;
00597        }
00598        RETVAL_ZVAL(element->obj, 1, 0);
00599 } /* }}} */
00600 
00601 /* {{{ proto mixed SplObjectStorage::getInfo()
00602  Returns associated information to current element */
00603 SPL_METHOD(SplObjectStorage, getInfo)
00604 {
00605        spl_SplObjectStorageElement *element;
00606        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00607 
00608        if (zend_parse_parameters_none() == FAILURE) {
00609               return;
00610        }
00611        
00612        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
00613               return;
00614        }
00615        RETVAL_ZVAL(element->inf, 1, 0);
00616 } /* }}} */
00617 
00618 /* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf)
00619  Sets associated information of current element to $inf */
00620 SPL_METHOD(SplObjectStorage, setInfo)
00621 {
00622        spl_SplObjectStorageElement *element;
00623        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00624        zval *inf;
00625        
00626        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) {
00627               return;
00628        }
00629 
00630        if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
00631               return;
00632        }
00633        zval_ptr_dtor(&element->inf);
00634        element->inf = inf;
00635        Z_ADDREF_P(inf);
00636 } /* }}} */
00637 
00638 /* {{{ proto void SplObjectStorage::next()
00639  Moves position forward */
00640 SPL_METHOD(SplObjectStorage, next)
00641 {
00642        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00643        
00644        if (zend_parse_parameters_none() == FAILURE) {
00645               return;
00646        }
00647        
00648        zend_hash_move_forward_ex(&intern->storage, &intern->pos);
00649        intern->index++;
00650 } /* }}} */
00651 
00652 /* {{{ proto string SplObjectStorage::serialize()
00653  Serializes storage */
00654 SPL_METHOD(SplObjectStorage, serialize)
00655 {
00656        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00657 
00658        spl_SplObjectStorageElement *element;
00659        zval members, *pmembers;
00660        HashPosition      pos;
00661        php_serialize_data_t var_hash;
00662        smart_str buf = {0};
00663 
00664        if (zend_parse_parameters_none() == FAILURE) {
00665               return;
00666        }
00667 
00668        PHP_VAR_SERIALIZE_INIT(var_hash);
00669        
00670        /* storage */
00671        smart_str_appendl(&buf, "x:i:", 4);
00672        smart_str_append_long(&buf, zend_hash_num_elements(&intern->storage));
00673        smart_str_appendc(&buf, ';');
00674 
00675        zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
00676 
00677        while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
00678               if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) {
00679                      smart_str_free(&buf);
00680                      PHP_VAR_SERIALIZE_DESTROY(var_hash);
00681                      RETURN_NULL();
00682               }
00683               php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC);
00684               smart_str_appendc(&buf, ',');
00685               php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC);
00686               smart_str_appendc(&buf, ';');
00687               zend_hash_move_forward_ex(&intern->storage, &pos);
00688        }
00689 
00690        /* members */
00691        smart_str_appendl(&buf, "m:", 2);
00692        INIT_PZVAL(&members);
00693        Z_ARRVAL(members) = intern->std.properties;
00694        Z_TYPE(members) = IS_ARRAY;
00695        pmembers = &members;
00696        php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
00697 
00698        /* done */
00699        PHP_VAR_SERIALIZE_DESTROY(var_hash);
00700 
00701        if (buf.c) {
00702               RETURN_STRINGL(buf.c, buf.len, 0);
00703        } else {
00704               RETURN_NULL();
00705        }
00706        
00707 } /* }}} */
00708 
00709 /* {{{ proto void SplObjectStorage::unserialize(string serialized)
00710  Unserializes storage */
00711 SPL_METHOD(SplObjectStorage, unserialize)
00712 {
00713        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00714 
00715        char *buf;
00716        int buf_len;
00717        const unsigned char *p, *s;
00718        php_unserialize_data_t var_hash;
00719        zval *pentry, *pmembers, *pcount = NULL, *pinf;
00720        long count;
00721        
00722        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
00723               return;
00724        }
00725 
00726        if (buf_len == 0) {
00727               zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
00728               return;
00729        }
00730 
00731        /* storage */
00732        s = p = (const unsigned char*)buf;
00733        PHP_VAR_UNSERIALIZE_INIT(var_hash);
00734 
00735        if (*p!= 'x' || *++p != ':') {
00736               goto outexcept;
00737        }
00738        ++p;
00739 
00740        ALLOC_INIT_ZVAL(pcount);
00741        if (!php_var_unserialize(&pcount, &p, s + buf_len, NULL TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
00742               zval_ptr_dtor(&pcount);
00743               goto outexcept;
00744        }
00745 
00746        --p; /* for ';' */
00747        count = Z_LVAL_P(pcount);
00748        zval_ptr_dtor(&pcount);
00749               
00750        while(count-- > 0) {
00751               spl_SplObjectStorageElement *pelement;
00752               
00753               if (*p != ';') {
00754                      goto outexcept;
00755               }
00756               ++p;
00757               if(*p != 'O' && *p != 'C' && *p != 'r') {
00758                      goto outexcept;
00759               }
00760               ALLOC_INIT_ZVAL(pentry);
00761               if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
00762                      zval_ptr_dtor(&pentry);
00763                      goto outexcept;
00764               }
00765               if(Z_TYPE_P(pentry) != IS_OBJECT) {
00766                      zval_ptr_dtor(&pentry);
00767                      goto outexcept;
00768               }
00769               ALLOC_INIT_ZVAL(pinf);
00770               if (*p == ',') { /* new version has inf */
00771                      ++p;
00772                      if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) {
00773                             zval_ptr_dtor(&pinf);
00774                             goto outexcept;
00775                      }
00776               }
00777               
00778               pelement = spl_object_storage_get(intern, pentry TSRMLS_CC);
00779               if(pelement) {
00780                      if(pelement->inf) {
00781                             var_push_dtor(&var_hash, &pelement->inf);
00782                      }
00783                      if(pelement->obj) {
00784                             var_push_dtor(&var_hash, &pelement->obj);
00785                      }
00786               } 
00787               spl_object_storage_attach(intern, pentry, pinf TSRMLS_CC);
00788               zval_ptr_dtor(&pentry);
00789               zval_ptr_dtor(&pinf);
00790        }
00791 
00792        if (*p != ';') {
00793               goto outexcept;
00794        }
00795        ++p;
00796 
00797        /* members */
00798        if (*p!= 'm' || *++p != ':') {
00799               goto outexcept;
00800        }
00801        ++p;
00802 
00803        ALLOC_INIT_ZVAL(pmembers);
00804        if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
00805               zval_ptr_dtor(&pmembers);
00806               goto outexcept;
00807        }
00808 
00809        /* copy members */
00810        zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
00811        zval_ptr_dtor(&pmembers);
00812 
00813        /* done reading $serialized */
00814 
00815        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
00816        return;
00817 
00818 outexcept:
00819        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
00820        zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
00821        return;
00822 
00823 } /* }}} */
00824 
00825 ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
00826        ZEND_ARG_INFO(0, object)
00827 ZEND_END_ARG_INFO();
00828 
00829 ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1)
00830        ZEND_ARG_INFO(0, object)
00831        ZEND_ARG_INFO(0, inf)
00832 ZEND_END_ARG_INFO();
00833 
00834 ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
00835        ZEND_ARG_INFO(0, serialized)
00836 ZEND_END_ARG_INFO();
00837 
00838 ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
00839        ZEND_ARG_INFO(0, info)
00840 ZEND_END_ARG_INFO();
00841 
00842 ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
00843        ZEND_ARG_INFO(0, object)
00844 ZEND_END_ARG_INFO()
00845 
00846 ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0)
00847 ZEND_END_ARG_INFO()
00848 
00849 static const zend_function_entry spl_funcs_SplObjectStorage[] = {
00850        SPL_ME(SplObjectStorage,  attach,      arginfo_attach,        0)
00851        SPL_ME(SplObjectStorage,  detach,      arginfo_Object,        0)
00852        SPL_ME(SplObjectStorage,  contains,    arginfo_Object,        0)
00853        SPL_ME(SplObjectStorage,  addAll,      arginfo_Object,        0)
00854        SPL_ME(SplObjectStorage,  removeAll,   arginfo_Object,        0)
00855        SPL_ME(SplObjectStorage,  removeAllExcept, arginfo_Object,    0)
00856        SPL_ME(SplObjectStorage,  getInfo,     arginfo_splobject_void,0)
00857        SPL_ME(SplObjectStorage,  setInfo,     arginfo_setInfo,       0)
00858        /* Countable */
00859        SPL_ME(SplObjectStorage,  count,       arginfo_splobject_void,0)
00860        /* Iterator */
00861        SPL_ME(SplObjectStorage,  rewind,      arginfo_splobject_void,0)
00862        SPL_ME(SplObjectStorage,  valid,       arginfo_splobject_void,0)
00863        SPL_ME(SplObjectStorage,  key,         arginfo_splobject_void,0)
00864        SPL_ME(SplObjectStorage,  current,     arginfo_splobject_void,0)
00865        SPL_ME(SplObjectStorage,  next,        arginfo_splobject_void,0)
00866        /* Serializable */
00867        SPL_ME(SplObjectStorage,  unserialize, arginfo_Serialized,    0)
00868        SPL_ME(SplObjectStorage,  serialize,   arginfo_splobject_void,0)
00869        /* ArrayAccess */
00870        SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0)
00871        SPL_MA(SplObjectStorage, offsetSet,    SplObjectStorage, attach,   arginfo_attach, 0)
00872        SPL_MA(SplObjectStorage, offsetUnset,  SplObjectStorage, detach,   arginfo_offsetGet, 0)
00873        SPL_ME(SplObjectStorage, offsetGet,    arginfo_offsetGet,     0)
00874        {NULL, NULL, NULL}
00875 };
00876 
00877 typedef enum {
00878        MIT_NEED_ANY     = 0,
00879        MIT_NEED_ALL     = 1,
00880        MIT_KEYS_NUMERIC = 0,
00881        MIT_KEYS_ASSOC   = 2
00882 } MultipleIteratorFlags;
00883 
00884 #define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT   1
00885 #define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY       2
00886 
00887 /* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC])
00888    Iterator that iterates over several iterators one after the other */
00889 SPL_METHOD(MultipleIterator, __construct)
00890 {
00891        spl_SplObjectStorage   *intern;
00892        long                    flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
00893        zend_error_handling error_handling;
00894 
00895        zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
00896 
00897        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
00898               zend_restore_error_handling(&error_handling TSRMLS_CC);
00899               return;
00900        }
00901 
00902        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00903        intern->flags = flags;
00904        zend_restore_error_handling(&error_handling TSRMLS_CC);
00905 }
00906 /* }}} */
00907 
00908 /* {{{ proto int MultipleIterator::getFlags()
00909    Return current flags */
00910 SPL_METHOD(MultipleIterator, getFlags)
00911 {
00912        spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00913        
00914        if (zend_parse_parameters_none() == FAILURE) {
00915               return;
00916        }
00917        RETURN_LONG(intern->flags);
00918 }
00919 /* }}} */
00920 
00921 /* {{{ proto int MultipleIterator::setFlags(int flags)
00922    Set flags */
00923 SPL_METHOD(MultipleIterator, setFlags)
00924 {
00925        spl_SplObjectStorage *intern;
00926        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00927 
00928        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
00929               return;
00930        }
00931 }
00932 /* }}} */
00933 
00934 /* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException
00935    Attach a new iterator */
00936 SPL_METHOD(MultipleIterator, attachIterator)
00937 {
00938        spl_SplObjectStorage        *intern;
00939        zval                        *iterator = NULL, *info = NULL;
00940 
00941        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
00942               return;
00943        }
00944 
00945        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00946 
00947        if (info != NULL) {
00948               spl_SplObjectStorageElement *element;
00949               zval                         compare_result;
00950 
00951               if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING) {
00952                      zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
00953                      return;
00954               }
00955 
00956               zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00957               while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
00958                      is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
00959                      if (Z_LVAL(compare_result)) {
00960                             zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
00961                             return;
00962                      }
00963                      zend_hash_move_forward_ex(&intern->storage, &intern->pos);
00964               }
00965        }
00966 
00967        spl_object_storage_attach(intern, iterator, info TSRMLS_CC);
00968 }
00969 /* }}} */
00970 
00971 /* {{{ proto void MultipleIterator::rewind()
00972    Rewind all attached iterator instances */
00973 SPL_METHOD(MultipleIterator, rewind)
00974 {
00975        spl_SplObjectStorage        *intern;
00976        spl_SplObjectStorageElement *element;
00977        zval                        *it;
00978 
00979        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
00980        
00981        if (zend_parse_parameters_none() == FAILURE) {
00982               return;
00983        }
00984 
00985        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
00986        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
00987               it = element->obj;
00988               zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
00989               zend_hash_move_forward_ex(&intern->storage, &intern->pos);
00990        }
00991 }
00992 /* }}} */
00993 
00994 /* {{{ proto void MultipleIterator::next()
00995    Move all attached iterator instances forward */
00996 SPL_METHOD(MultipleIterator, next)
00997 {
00998        spl_SplObjectStorage        *intern;
00999        spl_SplObjectStorageElement *element;
01000        zval                        *it;
01001 
01002        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
01003        
01004        if (zend_parse_parameters_none() == FAILURE) {
01005               return;
01006        }
01007 
01008        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
01009        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
01010               it = element->obj;
01011               zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
01012               zend_hash_move_forward_ex(&intern->storage, &intern->pos);
01013        }
01014 }
01015 /* }}} */
01016 
01017 /* {{{ proto bool MultipleIterator::valid()
01018    Return whether all or one sub iterator is valid depending on flags */
01019 SPL_METHOD(MultipleIterator, valid)
01020 {
01021        spl_SplObjectStorage        *intern;
01022        spl_SplObjectStorageElement *element;
01023        zval                        *it, *retval = NULL;
01024        long                         expect, valid;
01025 
01026        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
01027        
01028        if (zend_parse_parameters_none() == FAILURE) {
01029               return;
01030        }
01031 
01032        if (!zend_hash_num_elements(&intern->storage)) {
01033               RETURN_FALSE;
01034        }
01035 
01036        expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
01037 
01038        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
01039        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
01040               it = element->obj;
01041               zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
01042 
01043               if (retval) {
01044                      valid = Z_LVAL_P(retval);
01045                      zval_ptr_dtor(&retval);
01046               } else {
01047                      valid = 0;
01048               }
01049 
01050               if (expect != valid) {
01051                      RETURN_BOOL(!expect);
01052               }
01053 
01054               zend_hash_move_forward_ex(&intern->storage, &intern->pos);
01055        }
01056 
01057        RETURN_BOOL(expect);
01058 }
01059 /* }}} */
01060 
01061 static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
01062 {
01063        spl_SplObjectStorageElement *element;
01064        zval                        *it, *retval = NULL;
01065        int                          valid = 1, num_elements;
01066 
01067        num_elements = zend_hash_num_elements(&intern->storage);
01068        if (num_elements < 1) {
01069               RETURN_FALSE;
01070        }
01071 
01072        array_init_size(return_value, num_elements);
01073        
01074        zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
01075        while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
01076               it = element->obj;
01077               zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
01078 
01079               if (retval) {
01080                      valid = Z_LVAL_P(retval);
01081                      zval_ptr_dtor(&retval);
01082               } else {
01083                      valid = 0;
01084               }
01085 
01086               if (valid) {
01087                      if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
01088                             zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
01089                      } else {
01090                             zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key,     "key",     &retval);
01091                      }
01092                      if (!retval) {
01093                             zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
01094                             return;
01095                      }
01096               } else if (intern->flags & MIT_NEED_ALL) {
01097                      if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
01098                             zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
01099                      } else {
01100                             zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
01101                      }
01102                      return;
01103               } else {
01104                      ALLOC_INIT_ZVAL(retval);
01105               }
01106 
01107               if (intern->flags & MIT_KEYS_ASSOC) {
01108                      switch (Z_TYPE_P(element->inf)) {
01109                             case IS_LONG:
01110                                    add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
01111                                    break;
01112                             case IS_STRING:
01113                                    add_assoc_zval_ex(return_value, Z_STRVAL_P(element->inf), Z_STRLEN_P(element->inf)+1U, retval);
01114                                    break;
01115                             default:
01116                                    zval_ptr_dtor(&retval);
01117                                    zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
01118                                    return;
01119                      }
01120               } else {
01121                      add_next_index_zval(return_value, retval);
01122               }
01123 
01124               zend_hash_move_forward_ex(&intern->storage, &intern->pos);
01125        }
01126 }
01127 /* }}} */
01128 
01129 /* {{{ proto array current() throws RuntimeException throws InvalidArgumentException
01130    Return an array of all registered Iterator instances current() result */
01131 SPL_METHOD(MultipleIterator, current)
01132 {
01133        spl_SplObjectStorage        *intern;
01134        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
01135        
01136        if (zend_parse_parameters_none() == FAILURE) {
01137               return;
01138        }
01139 
01140        spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
01141 }
01142 /* }}} */
01143 
01144 /* {{{ proto array MultipleIterator::key()
01145    Return an array of all registered Iterator instances key() result */
01146 SPL_METHOD(MultipleIterator, key)
01147 {
01148        spl_SplObjectStorage        *intern;
01149        intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
01150        
01151        if (zend_parse_parameters_none() == FAILURE) {
01152               return;
01153        }
01154 
01155        spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
01156 }
01157 /* }}} */
01158 
01159 ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
01160        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
01161        ZEND_ARG_INFO(0, infos)
01162 ZEND_END_ARG_INFO();
01163 
01164 ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
01165        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
01166 ZEND_END_ARG_INFO();
01167 
01168 ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
01169        ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
01170 ZEND_END_ARG_INFO();
01171 
01172 ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1)
01173        ZEND_ARG_INFO(0, flags)
01174 ZEND_END_ARG_INFO();
01175 
01176 static const zend_function_entry spl_funcs_MultipleIterator[] = {
01177        SPL_ME(MultipleIterator,  __construct,            arginfo_MultipleIterator_setflags,          0)
01178        SPL_ME(MultipleIterator,  getFlags,               arginfo_splobject_void,                     0)
01179        SPL_ME(MultipleIterator,  setFlags,               arginfo_MultipleIterator_setflags,          0)
01180        SPL_ME(MultipleIterator,  attachIterator,         arginfo_MultipleIterator_attachIterator,    0)
01181        SPL_MA(MultipleIterator,  detachIterator,         SplObjectStorage, detach,   arginfo_MultipleIterator_detachIterator,   0)
01182        SPL_MA(MultipleIterator,  containsIterator,       SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
01183        SPL_MA(MultipleIterator,  countIterators,         SplObjectStorage, count,    arginfo_splobject_void,                    0)
01184        /* Iterator */
01185        SPL_ME(MultipleIterator,  rewind,                 arginfo_splobject_void,                     0)
01186        SPL_ME(MultipleIterator,  valid,                  arginfo_splobject_void,                     0)
01187        SPL_ME(MultipleIterator,  key,                    arginfo_splobject_void,                     0)
01188        SPL_ME(MultipleIterator,  current,                arginfo_splobject_void,                     0)
01189        SPL_ME(MultipleIterator,  next,                   arginfo_splobject_void,                     0)
01190        {NULL, NULL, NULL}
01191 };
01192 
01193 /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
01194 PHP_MINIT_FUNCTION(spl_observer)
01195 {
01196        REGISTER_SPL_INTERFACE(SplObserver);
01197        REGISTER_SPL_INTERFACE(SplSubject);
01198 
01199        REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
01200        memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
01201 
01202        spl_handler_SplObjectStorage.get_properties  = spl_object_storage_get_properties;
01203        spl_handler_SplObjectStorage.get_debug_info  = spl_object_storage_debug_info;
01204        spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects;
01205        spl_handler_SplObjectStorage.clone_obj       = spl_object_storage_clone;
01206 
01207        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
01208        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
01209        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
01210        REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
01211 
01212        REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
01213        REGISTER_SPL_ITERATOR(MultipleIterator);
01214 
01215        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY",     MIT_NEED_ANY);
01216        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL",     MIT_NEED_ALL);
01217        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
01218        REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC",   MIT_KEYS_ASSOC);
01219 
01220        return SUCCESS;
01221 }
01222 /* }}} */
01223 
01224 /*
01225  * Local variables:
01226  * tab-width: 4
01227  * c-basic-offset: 4
01228  * End:
01229  * vim600: fdm=marker
01230  * vim: noet sw=4 ts=4
01231  */