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