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