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>