root/ext/spl/spl_observer.c

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

DEFINITIONS

This source file includes following definitions.
  1. spl_object_storage_from_obj
  2. spl_SplObjectStorage_free_storage
  3. spl_object_storage_get_hash
  4. spl_object_storage_free_hash
  5. spl_object_storage_dtor
  6. spl_object_storage_get
  7. spl_object_storage_attach
  8. spl_object_storage_detach
  9. spl_object_storage_addall
  10. spl_object_storage_new_ex
  11. spl_object_storage_clone
  12. spl_object_storage_debug_info
  13. spl_object_storage_get_gc
  14. spl_object_storage_compare_info
  15. spl_object_storage_compare_objects
  16. spl_SplObjectStorage_new
  17. spl_object_storage_contains
  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_METHOD
  43. spl_multiple_iterator_get_all
  44. SPL_METHOD
  45. SPL_METHOD
  46. PHP_MINIT_FUNCTION

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

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