root/ext/spl/spl_observer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. spl_SplOjectStorage_free_storage
  2. spl_object_storage_get_hash
  3. spl_object_storage_free_hash
  4. spl_object_storage_dtor
  5. spl_object_storage_get
  6. spl_object_storage_attach
  7. spl_object_storage_detach
  8. spl_object_storage_addall
  9. spl_object_storage_new_ex
  10. spl_object_storage_clone
  11. spl_object_storage_debug_info
  12. spl_object_storage_get_gc
  13. spl_object_storage_compare_info
  14. spl_object_storage_compare_objects
  15. spl_SplObjectStorage_new
  16. spl_object_storage_contains
  17. SPL_METHOD
  18. SPL_METHOD
  19. SPL_METHOD
  20. SPL_METHOD
  21. SPL_METHOD
  22. SPL_METHOD
  23. SPL_METHOD
  24. SPL_METHOD
  25. SPL_METHOD
  26. SPL_METHOD
  27. SPL_METHOD
  28. SPL_METHOD
  29. SPL_METHOD
  30. SPL_METHOD
  31. SPL_METHOD
  32. SPL_METHOD
  33. SPL_METHOD
  34. SPL_METHOD
  35. SPL_METHOD
  36. SPL_METHOD
  37. SPL_METHOD
  38. SPL_METHOD
  39. SPL_METHOD
  40. SPL_METHOD
  41. SPL_METHOD
  42. spl_multiple_iterator_get_all
  43. SPL_METHOD
  44. SPL_METHOD
  45. PHP_MINIT_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */