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