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