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