Annotation of embedaddon/php/ext/spl/spl_observer.c, revision 1.1.1.2
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:
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
364: * This is very hacky, but unfortunately the garbage collector can only query objects for
365: * dependencies through get_properties */
366: static HashTable *spl_object_storage_get_properties(zval *obj TSRMLS_DC) /* {{{ */
367: {
368: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(obj TSRMLS_CC);
369: spl_SplObjectStorageElement *element;
370: HashTable *props;
371: HashPosition pos;
372: zval *gcdata_arr = NULL,
373: **gcdata_arr_pp;
374:
375: props = std_object_handlers.get_properties(obj TSRMLS_CC);
376:
377: if (!GC_G(gc_active)) {
378: zend_hash_del(props, "\x00gcdata", sizeof("\x00gcdata"));
379: return props;
380: }
381:
382: if (props->nApplyCount > 0) {
383: return props;
384: }
385:
386: /* clean \x00gcdata, as it may be out of date */
387: if (zend_hash_find(props, "\x00gcdata", sizeof("\x00gcdata"), (void**) &gcdata_arr_pp) == SUCCESS) {
388: gcdata_arr = *gcdata_arr_pp;
389: zend_hash_clean(Z_ARRVAL_P(gcdata_arr));
390: }
391:
392: if (gcdata_arr == NULL) {
393: MAKE_STD_ZVAL(gcdata_arr);
394: array_init(gcdata_arr);
395: /* don't decrease refcount of members when destroying */
396: Z_ARRVAL_P(gcdata_arr)->pDestructor = NULL;
397:
398: /* name starts with \x00 to make tampering in user-land more difficult */
399: zend_hash_add(props, "\x00gcdata", sizeof("\x00gcdata"), &gcdata_arr, sizeof(gcdata_arr), NULL);
400: }
401:
402: zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
403: while (zend_hash_get_current_data_ex(&intern->storage, (void **)&element, &pos) == SUCCESS) {
404: add_next_index_zval(gcdata_arr, element->obj);
405: add_next_index_zval(gcdata_arr, element->inf);
406: zend_hash_move_forward_ex(&intern->storage, &pos);
407: }
408:
409: return props;
410: }
411: /* }}} */
412:
413: static int spl_object_storage_compare_info(spl_SplObjectStorageElement *e1, spl_SplObjectStorageElement *e2 TSRMLS_DC) /* {{{ */
414: {
415: zval result;
416:
417: if (compare_function(&result, e1->inf, e2->inf TSRMLS_CC) == FAILURE) {
418: return 1;
419: }
420:
421: return Z_LVAL(result);
422: }
423: /* }}} */
424:
425: static int spl_object_storage_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
426: {
427: zend_object *zo1 = (zend_object *)zend_object_store_get_object(o1 TSRMLS_CC);
428: zend_object *zo2 = (zend_object *)zend_object_store_get_object(o2 TSRMLS_CC);
429:
430: if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
431: return 1;
432: }
433:
434: return zend_hash_compare(&((spl_SplObjectStorage *)zo1)->storage, &((spl_SplObjectStorage *)zo2)->storage, (compare_func_t) spl_object_storage_compare_info, 0 TSRMLS_CC);
435: }
436: /* }}} */
437:
438: /* {{{ spl_array_object_new */
439: static zend_object_value spl_SplObjectStorage_new(zend_class_entry *class_type TSRMLS_DC)
440: {
441: spl_SplObjectStorage *tmp;
442: return spl_object_storage_new_ex(class_type, &tmp, NULL TSRMLS_CC);
443: }
444: /* }}} */
445:
1.1.1.2 ! misho 446: int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *this, zval *obj TSRMLS_DC) /* {{{ */
1.1 misho 447: {
1.1.1.2 ! misho 448: int hash_len, found;
! 449: char *hash = spl_object_storage_get_hash(intern, this, obj, &hash_len TSRMLS_CC);
! 450: if (!hash) {
! 451: return 0;
1.1 misho 452: }
1.1.1.2 ! misho 453:
! 454: found = zend_hash_exists(&intern->storage, hash, hash_len);
! 455: spl_object_storage_free_hash(intern, hash);
! 456: return found;
1.1 misho 457: } /* }}} */
458:
459: /* {{{ proto void SplObjectStorage::attach($obj, $inf = NULL)
460: Attaches an object to the storage if not yet contained */
461: SPL_METHOD(SplObjectStorage, attach)
462: {
463: zval *obj, *inf = NULL;
464:
465: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
466:
467: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o|z!", &obj, &inf) == FAILURE) {
468: return;
469: }
1.1.1.2 ! misho 470: spl_object_storage_attach(intern, getThis(), obj, inf TSRMLS_CC);
1.1 misho 471: } /* }}} */
472:
473: /* {{{ proto void SplObjectStorage::detach($obj)
474: Detaches an object from the storage */
475: SPL_METHOD(SplObjectStorage, detach)
476: {
477: zval *obj;
478: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
479:
480: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
481: return;
482: }
1.1.1.2 ! misho 483: spl_object_storage_detach(intern, getThis(), obj TSRMLS_CC);
1.1 misho 484:
485: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
486: intern->index = 0;
487: } /* }}} */
488:
1.1.1.2 ! misho 489: /* {{{ proto string SplObjectStorage::getHash($object)
! 490: Returns the hash of an object */
! 491: SPL_METHOD(SplObjectStorage, getHash)
! 492: {
! 493: zval *obj;
! 494: char *hash;
! 495:
! 496: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
! 497: return;
! 498: }
! 499:
! 500: hash = emalloc(33);
! 501: php_spl_object_hash(obj, hash TSRMLS_CC);
! 502:
! 503: RETVAL_STRING(hash, 0);
! 504:
! 505: } /* }}} */
! 506:
1.1 misho 507: /* {{{ proto mixed SplObjectStorage::offsetGet($object)
508: Returns associated information for a stored object */
509: SPL_METHOD(SplObjectStorage, offsetGet)
510: {
511: zval *obj;
512: spl_SplObjectStorageElement *element;
513: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1.1.1.2 ! misho 514: char *hash;
! 515: int hash_len;
! 516:
1.1 misho 517: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
518: return;
519: }
1.1.1.2 ! misho 520:
! 521: hash = spl_object_storage_get_hash(intern, getThis(), obj, &hash_len TSRMLS_CC);
! 522: if (!hash) {
! 523: return;
! 524: }
! 525:
! 526: element = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
! 527: spl_object_storage_free_hash(intern, hash);
! 528:
1.1 misho 529: if (!element) {
530: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Object not found");
531: } else {
532: RETURN_ZVAL(element->inf,1, 0);
533: }
534: } /* }}} */
535:
536: /* {{{ proto bool SplObjectStorage::addAll(SplObjectStorage $os)
537: Add all elements contained in $os */
538: SPL_METHOD(SplObjectStorage, addAll)
539: {
540: zval *obj;
541: spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
542: spl_SplObjectStorage *other;
543:
544: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
545: return;
546: }
547:
548: other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
549:
1.1.1.2 ! misho 550: spl_object_storage_addall(intern, getThis(), other TSRMLS_CC);
1.1 misho 551:
552: RETURN_LONG(zend_hash_num_elements(&intern->storage));
553: } /* }}} */
554:
555: /* {{{ proto bool SplObjectStorage::removeAll(SplObjectStorage $os)
556: Remove all elements contained in $os */
557: SPL_METHOD(SplObjectStorage, removeAll)
558: {
559: zval *obj;
560: spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
561: spl_SplObjectStorage *other;
562: spl_SplObjectStorageElement *element;
563:
564: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
565: return;
566: }
567:
568: other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
569:
570: zend_hash_internal_pointer_reset(&other->storage);
571: while (zend_hash_get_current_data(&other->storage, (void **)&element) == SUCCESS) {
1.1.1.2 ! misho 572: if (spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC) == FAILURE) {
1.1 misho 573: zend_hash_move_forward(&other->storage);
574: }
575: }
576:
577: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
578: intern->index = 0;
579:
580: RETURN_LONG(zend_hash_num_elements(&intern->storage));
581: } /* }}} */
582:
583: /* {{{ proto bool SplObjectStorage::removeAllExcept(SplObjectStorage $os)
584: Remove elements not common to both this SplObjectStorage instance and $os */
585: SPL_METHOD(SplObjectStorage, removeAllExcept)
586: {
587: zval *obj;
588: spl_SplObjectStorage *intern = (spl_SplObjectStorage *)zend_object_store_get_object(getThis() TSRMLS_CC);
589: spl_SplObjectStorage *other;
590: spl_SplObjectStorageElement *element;
591:
592: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &obj, spl_ce_SplObjectStorage) == FAILURE) {
593: return;
594: }
595:
596: other = (spl_SplObjectStorage *)zend_object_store_get_object(obj TSRMLS_CC);
597:
598: zend_hash_internal_pointer_reset(&intern->storage);
599: while (zend_hash_get_current_data(&intern->storage, (void **)&element) == SUCCESS) {
1.1.1.2 ! misho 600: if (!spl_object_storage_contains(other, getThis(), element->obj TSRMLS_CC)) {
! 601: spl_object_storage_detach(intern, getThis(), element->obj TSRMLS_CC);
1.1 misho 602: }
603: zend_hash_move_forward(&intern->storage);
604: }
605:
606: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
607: intern->index = 0;
608:
609: RETURN_LONG(zend_hash_num_elements(&intern->storage));
610: }
611: /* }}} */
612:
613: /* {{{ proto bool SplObjectStorage::contains($obj)
614: Determine whethe an object is contained in the storage */
615: SPL_METHOD(SplObjectStorage, contains)
616: {
617: zval *obj;
618: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
619:
620: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) {
621: return;
622: }
1.1.1.2 ! misho 623: RETURN_BOOL(spl_object_storage_contains(intern, getThis(), obj TSRMLS_CC));
1.1 misho 624: } /* }}} */
625:
626: /* {{{ proto int SplObjectStorage::count()
627: Determine number of objects in storage */
628: SPL_METHOD(SplObjectStorage, count)
629: {
630: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
631:
632: if (zend_parse_parameters_none() == FAILURE) {
633: return;
634: }
635:
636: RETURN_LONG(zend_hash_num_elements(&intern->storage));
637: } /* }}} */
638:
639: /* {{{ proto void SplObjectStorage::rewind()
640: Rewind to first position */
641: SPL_METHOD(SplObjectStorage, rewind)
642: {
643: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
644:
645: if (zend_parse_parameters_none() == FAILURE) {
646: return;
647: }
648:
649: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
650: intern->index = 0;
651: } /* }}} */
652:
653: /* {{{ proto bool SplObjectStorage::valid()
654: Returns whether current position is valid */
655: SPL_METHOD(SplObjectStorage, valid)
656: {
657: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
658:
659: if (zend_parse_parameters_none() == FAILURE) {
660: return;
661: }
662:
663: RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
664: } /* }}} */
665:
666: /* {{{ proto mixed SplObjectStorage::key()
667: Returns current key */
668: SPL_METHOD(SplObjectStorage, key)
669: {
670: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
671:
672: if (zend_parse_parameters_none() == FAILURE) {
673: return;
674: }
675:
676: RETURN_LONG(intern->index);
677: } /* }}} */
678:
679: /* {{{ proto mixed SplObjectStorage::current()
680: Returns current element */
681: SPL_METHOD(SplObjectStorage, current)
682: {
683: spl_SplObjectStorageElement *element;
684: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
685:
686: if (zend_parse_parameters_none() == FAILURE) {
687: return;
688: }
689:
690: if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
691: return;
692: }
693: RETVAL_ZVAL(element->obj, 1, 0);
694: } /* }}} */
695:
696: /* {{{ proto mixed SplObjectStorage::getInfo()
697: Returns associated information to current element */
698: SPL_METHOD(SplObjectStorage, getInfo)
699: {
700: spl_SplObjectStorageElement *element;
701: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
702:
703: if (zend_parse_parameters_none() == FAILURE) {
704: return;
705: }
706:
707: if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
708: return;
709: }
710: RETVAL_ZVAL(element->inf, 1, 0);
711: } /* }}} */
712:
713: /* {{{ proto mixed SplObjectStorage::setInfo(mixed $inf)
714: Sets associated information of current element to $inf */
715: SPL_METHOD(SplObjectStorage, setInfo)
716: {
717: spl_SplObjectStorageElement *element;
718: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
719: zval *inf;
720:
721: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &inf) == FAILURE) {
722: return;
723: }
724:
725: if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == FAILURE) {
726: return;
727: }
728: zval_ptr_dtor(&element->inf);
729: element->inf = inf;
730: Z_ADDREF_P(inf);
731: } /* }}} */
732:
733: /* {{{ proto void SplObjectStorage::next()
734: Moves position forward */
735: SPL_METHOD(SplObjectStorage, next)
736: {
737: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
738:
739: if (zend_parse_parameters_none() == FAILURE) {
740: return;
741: }
742:
743: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
744: intern->index++;
745: } /* }}} */
746:
747: /* {{{ proto string SplObjectStorage::serialize()
748: Serializes storage */
749: SPL_METHOD(SplObjectStorage, serialize)
750: {
751: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
752:
753: spl_SplObjectStorageElement *element;
1.1.1.2 ! misho 754: zval members, *pmembers, *flags;
1.1 misho 755: HashPosition pos;
756: php_serialize_data_t var_hash;
757: smart_str buf = {0};
758:
759: if (zend_parse_parameters_none() == FAILURE) {
760: return;
761: }
762:
763: PHP_VAR_SERIALIZE_INIT(var_hash);
764:
765: /* storage */
1.1.1.2 ! misho 766: smart_str_appendl(&buf, "x:", 2);
! 767: MAKE_STD_ZVAL(flags);
! 768: ZVAL_LONG(flags, zend_hash_num_elements(&intern->storage));
! 769: php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
! 770: zval_ptr_dtor(&flags);
1.1 misho 771:
772: zend_hash_internal_pointer_reset_ex(&intern->storage, &pos);
773:
774: while(zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
775: if (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &pos) == FAILURE) {
776: smart_str_free(&buf);
777: PHP_VAR_SERIALIZE_DESTROY(var_hash);
778: RETURN_NULL();
779: }
780: php_var_serialize(&buf, &element->obj, &var_hash TSRMLS_CC);
781: smart_str_appendc(&buf, ',');
782: php_var_serialize(&buf, &element->inf, &var_hash TSRMLS_CC);
783: smart_str_appendc(&buf, ';');
784: zend_hash_move_forward_ex(&intern->storage, &pos);
785: }
786:
787: /* members */
788: smart_str_appendl(&buf, "m:", 2);
789: INIT_PZVAL(&members);
1.1.1.2 ! misho 790: Z_ARRVAL(members) = zend_std_get_properties(getThis() TSRMLS_CC);
1.1 misho 791: Z_TYPE(members) = IS_ARRAY;
792: pmembers = &members;
793: php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
794:
795: /* done */
796: PHP_VAR_SERIALIZE_DESTROY(var_hash);
797:
798: if (buf.c) {
799: RETURN_STRINGL(buf.c, buf.len, 0);
800: } else {
801: RETURN_NULL();
802: }
803:
804: } /* }}} */
805:
806: /* {{{ proto void SplObjectStorage::unserialize(string serialized)
807: Unserializes storage */
808: SPL_METHOD(SplObjectStorage, unserialize)
809: {
810: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
811:
812: char *buf;
813: int buf_len;
814: const unsigned char *p, *s;
815: php_unserialize_data_t var_hash;
816: zval *pentry, *pmembers, *pcount = NULL, *pinf;
817: long count;
818:
819: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
820: return;
821: }
822:
823: if (buf_len == 0) {
824: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
825: return;
826: }
827:
828: /* storage */
829: s = p = (const unsigned char*)buf;
830: PHP_VAR_UNSERIALIZE_INIT(var_hash);
831:
832: if (*p!= 'x' || *++p != ':') {
833: goto outexcept;
834: }
835: ++p;
836:
837: ALLOC_INIT_ZVAL(pcount);
1.1.1.2 ! misho 838: if (!php_var_unserialize(&pcount, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pcount) != IS_LONG) {
1.1 misho 839: goto outexcept;
840: }
841:
842: --p; /* for ';' */
843: count = Z_LVAL_P(pcount);
844:
845: while(count-- > 0) {
846: spl_SplObjectStorageElement *pelement;
1.1.1.2 ! misho 847: char *hash;
! 848: int hash_len;
1.1 misho 849:
850: if (*p != ';') {
851: goto outexcept;
852: }
853: ++p;
854: if(*p != 'O' && *p != 'C' && *p != 'r') {
855: goto outexcept;
856: }
857: ALLOC_INIT_ZVAL(pentry);
858: if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) {
859: zval_ptr_dtor(&pentry);
860: goto outexcept;
861: }
862: if(Z_TYPE_P(pentry) != IS_OBJECT) {
863: zval_ptr_dtor(&pentry);
864: goto outexcept;
865: }
866: ALLOC_INIT_ZVAL(pinf);
867: if (*p == ',') { /* new version has inf */
868: ++p;
869: if (!php_var_unserialize(&pinf, &p, s + buf_len, &var_hash TSRMLS_CC)) {
870: zval_ptr_dtor(&pinf);
871: goto outexcept;
872: }
873: }
1.1.1.2 ! misho 874:
! 875: hash = spl_object_storage_get_hash(intern, getThis(), pentry, &hash_len TSRMLS_CC);
! 876: if (!hash) {
! 877: zval_ptr_dtor(&pentry);
! 878: zval_ptr_dtor(&pinf);
! 879: goto outexcept;
! 880: }
! 881: pelement = spl_object_storage_get(intern, hash, hash_len TSRMLS_CC);
! 882: spl_object_storage_free_hash(intern, hash);
1.1 misho 883: if(pelement) {
884: if(pelement->inf) {
885: var_push_dtor(&var_hash, &pelement->inf);
886: }
887: if(pelement->obj) {
888: var_push_dtor(&var_hash, &pelement->obj);
889: }
890: }
1.1.1.2 ! misho 891: spl_object_storage_attach(intern, getThis(), pentry, pinf TSRMLS_CC);
1.1 misho 892: zval_ptr_dtor(&pentry);
893: zval_ptr_dtor(&pinf);
894: }
895:
896: if (*p != ';') {
897: goto outexcept;
898: }
899: ++p;
900:
901: /* members */
902: if (*p!= 'm' || *++p != ':') {
903: goto outexcept;
904: }
905: ++p;
906:
907: ALLOC_INIT_ZVAL(pmembers);
908: if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
909: zval_ptr_dtor(&pmembers);
910: goto outexcept;
911: }
912:
913: /* copy members */
1.1.1.2 ! misho 914: if (!intern->std.properties) {
! 915: rebuild_object_properties(&intern->std);
! 916: }
1.1 misho 917: zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
918: zval_ptr_dtor(&pmembers);
919:
920: /* done reading $serialized */
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: return;
926:
927: outexcept:
1.1.1.2 ! misho 928: if (pcount) {
! 929: zval_ptr_dtor(&pcount);
! 930: }
1.1 misho 931: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
932: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
933: return;
934:
935: } /* }}} */
936:
937: ZEND_BEGIN_ARG_INFO(arginfo_Object, 0)
938: ZEND_ARG_INFO(0, object)
939: ZEND_END_ARG_INFO();
940:
941: ZEND_BEGIN_ARG_INFO_EX(arginfo_attach, 0, 0, 1)
942: ZEND_ARG_INFO(0, object)
943: ZEND_ARG_INFO(0, inf)
944: ZEND_END_ARG_INFO();
945:
946: ZEND_BEGIN_ARG_INFO(arginfo_Serialized, 0)
947: ZEND_ARG_INFO(0, serialized)
948: ZEND_END_ARG_INFO();
949:
950: ZEND_BEGIN_ARG_INFO(arginfo_setInfo, 0)
951: ZEND_ARG_INFO(0, info)
952: ZEND_END_ARG_INFO();
953:
1.1.1.2 ! misho 954: ZEND_BEGIN_ARG_INFO(arginfo_getHash, 0)
! 955: ZEND_ARG_INFO(0, object)
! 956: ZEND_END_ARG_INFO();
! 957:
1.1 misho 958: ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
959: ZEND_ARG_INFO(0, object)
960: ZEND_END_ARG_INFO()
961:
962: ZEND_BEGIN_ARG_INFO(arginfo_splobject_void, 0)
963: ZEND_END_ARG_INFO()
964:
965: static const zend_function_entry spl_funcs_SplObjectStorage[] = {
966: SPL_ME(SplObjectStorage, attach, arginfo_attach, 0)
967: SPL_ME(SplObjectStorage, detach, arginfo_Object, 0)
968: SPL_ME(SplObjectStorage, contains, arginfo_Object, 0)
969: SPL_ME(SplObjectStorage, addAll, arginfo_Object, 0)
970: SPL_ME(SplObjectStorage, removeAll, arginfo_Object, 0)
1.1.1.2 ! misho 971: SPL_ME(SplObjectStorage, removeAllExcept, arginfo_Object, 0)
1.1 misho 972: SPL_ME(SplObjectStorage, getInfo, arginfo_splobject_void,0)
973: SPL_ME(SplObjectStorage, setInfo, arginfo_setInfo, 0)
1.1.1.2 ! misho 974: SPL_ME(SplObjectStorage, getHash, arginfo_getHash, 0)
1.1 misho 975: /* Countable */
976: SPL_ME(SplObjectStorage, count, arginfo_splobject_void,0)
977: /* Iterator */
978: SPL_ME(SplObjectStorage, rewind, arginfo_splobject_void,0)
979: SPL_ME(SplObjectStorage, valid, arginfo_splobject_void,0)
980: SPL_ME(SplObjectStorage, key, arginfo_splobject_void,0)
981: SPL_ME(SplObjectStorage, current, arginfo_splobject_void,0)
982: SPL_ME(SplObjectStorage, next, arginfo_splobject_void,0)
983: /* Serializable */
984: SPL_ME(SplObjectStorage, unserialize, arginfo_Serialized, 0)
985: SPL_ME(SplObjectStorage, serialize, arginfo_splobject_void,0)
986: /* ArrayAccess */
987: SPL_MA(SplObjectStorage, offsetExists, SplObjectStorage, contains, arginfo_offsetGet, 0)
988: SPL_MA(SplObjectStorage, offsetSet, SplObjectStorage, attach, arginfo_attach, 0)
989: SPL_MA(SplObjectStorage, offsetUnset, SplObjectStorage, detach, arginfo_offsetGet, 0)
990: SPL_ME(SplObjectStorage, offsetGet, arginfo_offsetGet, 0)
991: {NULL, NULL, NULL}
992: };
993:
994: typedef enum {
995: MIT_NEED_ANY = 0,
996: MIT_NEED_ALL = 1,
997: MIT_KEYS_NUMERIC = 0,
998: MIT_KEYS_ASSOC = 2
999: } MultipleIteratorFlags;
1000:
1001: #define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1
1002: #define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2
1003:
1004: /* {{{ proto void MultipleIterator::__construct([int flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC])
1005: Iterator that iterates over several iterators one after the other */
1006: SPL_METHOD(MultipleIterator, __construct)
1007: {
1008: spl_SplObjectStorage *intern;
1009: long flags = MIT_NEED_ALL|MIT_KEYS_NUMERIC;
1010: zend_error_handling error_handling;
1011:
1012: zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
1013:
1014: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
1015: zend_restore_error_handling(&error_handling TSRMLS_CC);
1016: return;
1017: }
1018:
1019: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1020: intern->flags = flags;
1021: zend_restore_error_handling(&error_handling TSRMLS_CC);
1022: }
1023: /* }}} */
1024:
1025: /* {{{ proto int MultipleIterator::getFlags()
1026: Return current flags */
1027: SPL_METHOD(MultipleIterator, getFlags)
1028: {
1029: spl_SplObjectStorage *intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1030:
1031: if (zend_parse_parameters_none() == FAILURE) {
1032: return;
1033: }
1034: RETURN_LONG(intern->flags);
1035: }
1036: /* }}} */
1037:
1038: /* {{{ proto int MultipleIterator::setFlags(int flags)
1039: Set flags */
1040: SPL_METHOD(MultipleIterator, setFlags)
1041: {
1042: spl_SplObjectStorage *intern;
1043: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1044:
1045: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &intern->flags) == FAILURE) {
1046: return;
1047: }
1048: }
1049: /* }}} */
1050:
1051: /* {{{ proto void attachIterator(Iterator iterator[, mixed info]) throws InvalidArgumentException
1052: Attach a new iterator */
1053: SPL_METHOD(MultipleIterator, attachIterator)
1054: {
1055: spl_SplObjectStorage *intern;
1056: zval *iterator = NULL, *info = NULL;
1057:
1058: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|z!", &iterator, zend_ce_iterator, &info) == FAILURE) {
1059: return;
1060: }
1061:
1062: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1063:
1064: if (info != NULL) {
1065: spl_SplObjectStorageElement *element;
1066: zval compare_result;
1067:
1068: if (Z_TYPE_P(info) != IS_LONG && Z_TYPE_P(info) != IS_STRING) {
1069: zend_throw_exception(spl_ce_InvalidArgumentException, "Info must be NULL, integer or string", 0 TSRMLS_CC);
1070: return;
1071: }
1072:
1073: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
1074: while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS) {
1075: is_identical_function(&compare_result, info, element->inf TSRMLS_CC);
1076: if (Z_LVAL(compare_result)) {
1077: zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0 TSRMLS_CC);
1078: return;
1079: }
1080: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1081: }
1082: }
1083:
1.1.1.2 ! misho 1084: spl_object_storage_attach(intern, getThis(), iterator, info TSRMLS_CC);
1.1 misho 1085: }
1086: /* }}} */
1087:
1088: /* {{{ proto void MultipleIterator::rewind()
1089: Rewind all attached iterator instances */
1090: SPL_METHOD(MultipleIterator, rewind)
1091: {
1092: spl_SplObjectStorage *intern;
1093: spl_SplObjectStorageElement *element;
1094: zval *it;
1095:
1096: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1097:
1098: if (zend_parse_parameters_none() == FAILURE) {
1099: return;
1100: }
1101:
1102: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
1103: while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
1104: it = element->obj;
1105: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_rewind, "rewind", NULL);
1106: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1107: }
1108: }
1109: /* }}} */
1110:
1111: /* {{{ proto void MultipleIterator::next()
1112: Move all attached iterator instances forward */
1113: SPL_METHOD(MultipleIterator, next)
1114: {
1115: spl_SplObjectStorage *intern;
1116: spl_SplObjectStorageElement *element;
1117: zval *it;
1118:
1119: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1120:
1121: if (zend_parse_parameters_none() == FAILURE) {
1122: return;
1123: }
1124:
1125: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
1126: while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
1127: it = element->obj;
1128: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_next, "next", NULL);
1129: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1130: }
1131: }
1132: /* }}} */
1133:
1134: /* {{{ proto bool MultipleIterator::valid()
1135: Return whether all or one sub iterator is valid depending on flags */
1136: SPL_METHOD(MultipleIterator, valid)
1137: {
1138: spl_SplObjectStorage *intern;
1139: spl_SplObjectStorageElement *element;
1140: zval *it, *retval = NULL;
1141: long expect, valid;
1142:
1143: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1144:
1145: if (zend_parse_parameters_none() == FAILURE) {
1146: return;
1147: }
1148:
1149: if (!zend_hash_num_elements(&intern->storage)) {
1150: RETURN_FALSE;
1151: }
1152:
1153: expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
1154:
1155: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
1156: while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
1157: it = element->obj;
1158: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
1159:
1160: if (retval) {
1161: valid = Z_LVAL_P(retval);
1162: zval_ptr_dtor(&retval);
1163: } else {
1164: valid = 0;
1165: }
1166:
1167: if (expect != valid) {
1168: RETURN_BOOL(!expect);
1169: }
1170:
1171: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1172: }
1173:
1174: RETURN_BOOL(expect);
1175: }
1176: /* }}} */
1177:
1178: static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value TSRMLS_DC) /* {{{ */
1179: {
1180: spl_SplObjectStorageElement *element;
1181: zval *it, *retval = NULL;
1182: int valid = 1, num_elements;
1183:
1184: num_elements = zend_hash_num_elements(&intern->storage);
1185: if (num_elements < 1) {
1186: RETURN_FALSE;
1187: }
1188:
1189: array_init_size(return_value, num_elements);
1190:
1191: zend_hash_internal_pointer_reset_ex(&intern->storage, &intern->pos);
1192: while (zend_hash_get_current_data_ex(&intern->storage, (void**)&element, &intern->pos) == SUCCESS && !EG(exception)) {
1193: it = element->obj;
1194: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_valid, "valid", &retval);
1195:
1196: if (retval) {
1197: valid = Z_LVAL_P(retval);
1198: zval_ptr_dtor(&retval);
1199: } else {
1200: valid = 0;
1201: }
1202:
1203: if (valid) {
1204: if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
1205: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_current, "current", &retval);
1206: } else {
1207: zend_call_method_with_0_params(&it, Z_OBJCE_P(it), &Z_OBJCE_P(it)->iterator_funcs.zf_key, "key", &retval);
1208: }
1209: if (!retval) {
1210: zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0 TSRMLS_CC);
1211: return;
1212: }
1213: } else if (intern->flags & MIT_NEED_ALL) {
1214: if (SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT == get_type) {
1215: zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0 TSRMLS_CC);
1216: } else {
1217: zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0 TSRMLS_CC);
1218: }
1219: return;
1220: } else {
1221: ALLOC_INIT_ZVAL(retval);
1222: }
1223:
1224: if (intern->flags & MIT_KEYS_ASSOC) {
1225: switch (Z_TYPE_P(element->inf)) {
1226: case IS_LONG:
1227: add_index_zval(return_value, Z_LVAL_P(element->inf), retval);
1228: break;
1229: case IS_STRING:
1230: add_assoc_zval_ex(return_value, Z_STRVAL_P(element->inf), Z_STRLEN_P(element->inf)+1U, retval);
1231: break;
1232: default:
1233: zval_ptr_dtor(&retval);
1234: zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0 TSRMLS_CC);
1235: return;
1236: }
1237: } else {
1238: add_next_index_zval(return_value, retval);
1239: }
1240:
1241: zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1242: }
1243: }
1244: /* }}} */
1245:
1246: /* {{{ proto array current() throws RuntimeException throws InvalidArgumentException
1247: Return an array of all registered Iterator instances current() result */
1248: SPL_METHOD(MultipleIterator, current)
1249: {
1250: spl_SplObjectStorage *intern;
1251: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1252:
1253: if (zend_parse_parameters_none() == FAILURE) {
1254: return;
1255: }
1256:
1257: spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value TSRMLS_CC);
1258: }
1259: /* }}} */
1260:
1261: /* {{{ proto array MultipleIterator::key()
1262: Return an array of all registered Iterator instances key() result */
1263: SPL_METHOD(MultipleIterator, key)
1264: {
1265: spl_SplObjectStorage *intern;
1266: intern = (spl_SplObjectStorage*)zend_object_store_get_object(getThis() TSRMLS_CC);
1267:
1268: if (zend_parse_parameters_none() == FAILURE) {
1269: return;
1270: }
1271:
1272: spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value TSRMLS_CC);
1273: }
1274: /* }}} */
1275:
1276: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_attachIterator, 0, 0, 1)
1277: ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1278: ZEND_ARG_INFO(0, infos)
1279: ZEND_END_ARG_INFO();
1280:
1281: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_detachIterator, 0, 0, 1)
1282: ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1283: ZEND_END_ARG_INFO();
1284:
1285: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_containsIterator, 0, 0, 1)
1286: ZEND_ARG_OBJ_INFO(0, iterator, Iterator, 0)
1287: ZEND_END_ARG_INFO();
1288:
1289: ZEND_BEGIN_ARG_INFO_EX(arginfo_MultipleIterator_setflags, 0, 0, 1)
1290: ZEND_ARG_INFO(0, flags)
1291: ZEND_END_ARG_INFO();
1292:
1293: static const zend_function_entry spl_funcs_MultipleIterator[] = {
1294: SPL_ME(MultipleIterator, __construct, arginfo_MultipleIterator_setflags, 0)
1295: SPL_ME(MultipleIterator, getFlags, arginfo_splobject_void, 0)
1296: SPL_ME(MultipleIterator, setFlags, arginfo_MultipleIterator_setflags, 0)
1297: SPL_ME(MultipleIterator, attachIterator, arginfo_MultipleIterator_attachIterator, 0)
1298: SPL_MA(MultipleIterator, detachIterator, SplObjectStorage, detach, arginfo_MultipleIterator_detachIterator, 0)
1299: SPL_MA(MultipleIterator, containsIterator, SplObjectStorage, contains, arginfo_MultipleIterator_containsIterator, 0)
1300: SPL_MA(MultipleIterator, countIterators, SplObjectStorage, count, arginfo_splobject_void, 0)
1301: /* Iterator */
1302: SPL_ME(MultipleIterator, rewind, arginfo_splobject_void, 0)
1303: SPL_ME(MultipleIterator, valid, arginfo_splobject_void, 0)
1304: SPL_ME(MultipleIterator, key, arginfo_splobject_void, 0)
1305: SPL_ME(MultipleIterator, current, arginfo_splobject_void, 0)
1306: SPL_ME(MultipleIterator, next, arginfo_splobject_void, 0)
1307: {NULL, NULL, NULL}
1308: };
1309:
1310: /* {{{ PHP_MINIT_FUNCTION(spl_observer) */
1311: PHP_MINIT_FUNCTION(spl_observer)
1312: {
1313: REGISTER_SPL_INTERFACE(SplObserver);
1314: REGISTER_SPL_INTERFACE(SplSubject);
1315:
1316: REGISTER_SPL_STD_CLASS_EX(SplObjectStorage, spl_SplObjectStorage_new, spl_funcs_SplObjectStorage);
1317: memcpy(&spl_handler_SplObjectStorage, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1318:
1319: spl_handler_SplObjectStorage.get_properties = spl_object_storage_get_properties;
1320: spl_handler_SplObjectStorage.get_debug_info = spl_object_storage_debug_info;
1321: spl_handler_SplObjectStorage.compare_objects = spl_object_storage_compare_objects;
1322: spl_handler_SplObjectStorage.clone_obj = spl_object_storage_clone;
1323:
1324: REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Countable);
1325: REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Iterator);
1326: REGISTER_SPL_IMPLEMENTS(SplObjectStorage, Serializable);
1327: REGISTER_SPL_IMPLEMENTS(SplObjectStorage, ArrayAccess);
1328:
1329: REGISTER_SPL_STD_CLASS_EX(MultipleIterator, spl_SplObjectStorage_new, spl_funcs_MultipleIterator);
1330: REGISTER_SPL_ITERATOR(MultipleIterator);
1331:
1332: REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ANY", MIT_NEED_ANY);
1333: REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_NEED_ALL", MIT_NEED_ALL);
1334: REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_NUMERIC", MIT_KEYS_NUMERIC);
1335: REGISTER_SPL_CLASS_CONST_LONG(MultipleIterator, "MIT_KEYS_ASSOC", MIT_KEYS_ASSOC);
1336:
1337: return SUCCESS;
1338: }
1339: /* }}} */
1340:
1341: /*
1342: * Local variables:
1343: * tab-width: 4
1344: * c-basic-offset: 4
1345: * End:
1346: * vim600: fdm=marker
1347: * vim: noet sw=4 ts=4
1348: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>