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