Annotation of embedaddon/php/ext/spl/spl_array.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 subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Marcus Boerger <helly@php.net> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 ! misho 19: /* $Id$ */
1.1 misho 20:
21: #ifdef HAVE_CONFIG_H
22: # include "config.h"
23: #endif
24:
25: #include "php.h"
26: #include "php_ini.h"
27: #include "ext/standard/info.h"
28: #include "ext/standard/php_var.h"
29: #include "ext/standard/php_smart_str.h"
30: #include "zend_interfaces.h"
31: #include "zend_exceptions.h"
32:
33: #include "php_spl.h"
34: #include "spl_functions.h"
35: #include "spl_engine.h"
36: #include "spl_iterators.h"
37: #include "spl_array.h"
38: #include "spl_exceptions.h"
39:
40: zend_object_handlers spl_handler_ArrayObject;
41: PHPAPI zend_class_entry *spl_ce_ArrayObject;
42:
43: zend_object_handlers spl_handler_ArrayIterator;
44: PHPAPI zend_class_entry *spl_ce_ArrayIterator;
45: PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
46:
47: #define SPL_ARRAY_STD_PROP_LIST 0x00000001
48: #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
49: #define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004
50: #define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
51: #define SPL_ARRAY_OVERLOADED_VALID 0x00020000
52: #define SPL_ARRAY_OVERLOADED_KEY 0x00040000
53: #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
54: #define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
55: #define SPL_ARRAY_IS_REF 0x01000000
56: #define SPL_ARRAY_IS_SELF 0x02000000
57: #define SPL_ARRAY_USE_OTHER 0x04000000
58: #define SPL_ARRAY_INT_MASK 0xFFFF0000
59: #define SPL_ARRAY_CLONE_MASK 0x0300FFFF
60:
61: typedef struct _spl_array_object {
1.1.1.2 ! misho 62: zend_object std;
! 63: zval *array;
! 64: zval *retval;
! 65: HashPosition pos;
! 66: ulong pos_h;
! 67: int ar_flags;
! 68: int is_self;
! 69: zend_function *fptr_offset_get;
! 70: zend_function *fptr_offset_set;
! 71: zend_function *fptr_offset_has;
! 72: zend_function *fptr_offset_del;
! 73: zend_function *fptr_count;
! 74: zend_class_entry* ce_get_iterator;
1.1 misho 75: HashTable *debug_info;
76: unsigned char nApplyCount;
77: } spl_array_object;
78:
79: static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
80: if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
1.1.1.2 ! misho 81: if (!intern->std.properties) {
! 82: rebuild_object_properties(&intern->std);
! 83: }
1.1 misho 84: return intern->std.properties;
85: } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
86: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
87: return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
88: } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
1.1.1.2 ! misho 89: if (!intern->std.properties) {
! 90: rebuild_object_properties(&intern->std);
! 91: }
1.1 misho 92: return intern->std.properties;
93: } else {
94: return HASH_OF(intern->array);
95: }
96: } /* }}} */
97:
98: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
99:
100: static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
101: {
102: Bucket *pos = intern->pos;
103: if (pos != NULL) {
104: intern->pos_h = pos->h;
105: }
106: } /* }}} */
107:
108: static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
109: {
110: intern->pos = pos;
111: spl_array_update_pos(intern);
112: } /* }}} */
113:
114: SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
115: {
116: Bucket *p;
117:
118: /* IS_CONSISTENT(ht);*/
119:
120: /* HASH_PROTECT_RECURSION(ht);*/
121: p = ht->arBuckets[intern->pos_h & ht->nTableMask];
122: while (p != NULL) {
123: if (p == intern->pos) {
124: return SUCCESS;
125: }
126: p = p->pNext;
127: }
128: /* HASH_UNPROTECT_RECURSION(ht); */
129: spl_array_rewind(intern TSRMLS_CC);
130: return FAILURE;
131:
132: } /* }}} */
133:
134: SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
135: {
136: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
137: return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
138: }
139: /* }}} */
140:
141: /* {{{ spl_array_object_free_storage */
142: static void spl_array_object_free_storage(void *object TSRMLS_DC)
143: {
144: spl_array_object *intern = (spl_array_object *)object;
145:
146: zend_object_std_dtor(&intern->std TSRMLS_CC);
147:
148: zval_ptr_dtor(&intern->array);
149: zval_ptr_dtor(&intern->retval);
150:
151: if (intern->debug_info != NULL) {
152: zend_hash_destroy(intern->debug_info);
153: efree(intern->debug_info);
154: }
155:
156: efree(object);
157: }
158: /* }}} */
159:
160: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
161:
162: /* {{{ spl_array_object_new_ex */
163: static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
164: {
165: zend_object_value retval;
166: spl_array_object *intern;
167: zval *tmp;
168: zend_class_entry * parent = class_type;
169: int inherited = 0;
170:
171: intern = emalloc(sizeof(spl_array_object));
172: memset(intern, 0, sizeof(spl_array_object));
173: *obj = intern;
174: ALLOC_INIT_ZVAL(intern->retval);
175:
176: zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1.1.1.2 ! misho 177: object_properties_init(&intern->std, class_type);
1.1 misho 178:
179: intern->ar_flags = 0;
180: intern->debug_info = NULL;
181: intern->ce_get_iterator = spl_ce_ArrayIterator;
182: if (orig) {
183: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
184:
185: intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
186: intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
187: intern->ce_get_iterator = other->ce_get_iterator;
188: if (clone_orig) {
189: intern->array = other->array;
190: if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
191: MAKE_STD_ZVAL(intern->array);
192: array_init(intern->array);
193: zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
194: }
195: if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
196: Z_ADDREF_P(other->array);
197: }
198: } else {
199: intern->array = orig;
200: Z_ADDREF_P(intern->array);
201: intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
202: }
203: } else {
204: MAKE_STD_ZVAL(intern->array);
205: array_init(intern->array);
206: intern->ar_flags &= ~SPL_ARRAY_IS_REF;
207: }
208:
209: retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
210: while (parent) {
211: if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
212: retval.handlers = &spl_handler_ArrayIterator;
213: class_type->get_iterator = spl_array_get_iterator;
214: break;
215: } else if (parent == spl_ce_ArrayObject) {
216: retval.handlers = &spl_handler_ArrayObject;
217: break;
218: }
219: parent = parent->parent;
220: inherited = 1;
221: }
222: if (!parent) { /* this must never happen */
223: php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
224: }
225: if (inherited) {
226: zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
227: if (intern->fptr_offset_get->common.scope == parent) {
228: intern->fptr_offset_get = NULL;
229: }
230: zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
231: if (intern->fptr_offset_set->common.scope == parent) {
232: intern->fptr_offset_set = NULL;
233: }
234: zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
235: if (intern->fptr_offset_has->common.scope == parent) {
236: intern->fptr_offset_has = NULL;
237: }
238: zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
239: if (intern->fptr_offset_del->common.scope == parent) {
240: intern->fptr_offset_del = NULL;
241: }
242: zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
243: if (intern->fptr_count->common.scope == parent) {
244: intern->fptr_count = NULL;
245: }
246: }
247: /* Cache iterator functions if ArrayIterator or derived. Check current's */
248: /* cache since only current is always required */
249: if (retval.handlers == &spl_handler_ArrayIterator) {
250: if (!class_type->iterator_funcs.zf_current) {
251: zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
252: zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
253: zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
254: zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
255: zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
256: }
257: if (inherited) {
258: if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
259: if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
260: if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
261: if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
262: if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
263: }
264: }
265:
266: spl_array_rewind(intern TSRMLS_CC);
267: return retval;
268: }
269: /* }}} */
270:
271: /* {{{ spl_array_object_new */
272: static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
273: {
274: spl_array_object *tmp;
275: return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
276: }
277: /* }}} */
278:
279: /* {{{ spl_array_object_clone */
280: static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
281: {
282: zend_object_value new_obj_val;
283: zend_object *old_object;
284: zend_object *new_object;
285: zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
286: spl_array_object *intern;
287:
288: old_object = zend_objects_get_address(zobject TSRMLS_CC);
289: new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
290: new_object = &intern->std;
291:
292: zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
293:
294: return new_obj_val;
295: }
296: /* }}} */
297:
298: static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
299: {
300: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
301: zval **retval;
302: long index;
303: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
304:
305: /* We cannot get the pointer pointer so we don't allow it here for now
306: if (check_inherited && intern->fptr_offset_get) {
307: return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
308: }*/
309:
310: if (!offset) {
311: return &EG(uninitialized_zval_ptr);
312: }
313:
314: if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
315: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
316: return &EG(uninitialized_zval_ptr);;
317: }
318:
319: switch(Z_TYPE_P(offset)) {
320: case IS_STRING:
321: if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
322: if (type == BP_VAR_W || type == BP_VAR_RW) {
323: zval *value;
324: ALLOC_INIT_ZVAL(value);
325: zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
1.1.1.2 ! misho 326: if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) != FAILURE) {
! 327: return retval;
! 328: } else {
! 329: return &EG(uninitialized_zval_ptr);
! 330: }
1.1 misho 331: } else {
332: zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset));
333: return &EG(uninitialized_zval_ptr);
334: }
335: } else {
336: return retval;
337: }
338: case IS_DOUBLE:
339: case IS_RESOURCE:
340: case IS_BOOL:
341: case IS_LONG:
342: if (offset->type == IS_DOUBLE) {
343: index = (long)Z_DVAL_P(offset);
344: } else {
345: index = Z_LVAL_P(offset);
346: }
347: if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
348: if (type == BP_VAR_W || type == BP_VAR_RW) {
349: zval *value;
350: ALLOC_INIT_ZVAL(value);
351: zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
1.1.1.2 ! misho 352: if (zend_hash_index_find(ht, index, (void **) &retval) != FAILURE) {
! 353: return retval;
! 354: } else {
! 355: return &EG(uninitialized_zval_ptr);
! 356: }
1.1 misho 357: } else {
358: zend_error(E_NOTICE, "Undefined offset: %ld", index);
359: return &EG(uninitialized_zval_ptr);
360: }
361: } else {
362: return retval;
363: }
364: break;
365: default:
366: zend_error(E_WARNING, "Illegal offset type");
367: return &EG(uninitialized_zval_ptr);
368: }
369: } /* }}} */
370:
371: static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
372: {
373: zval **ret;
374:
375: if (check_inherited) {
376: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
377: if (intern->fptr_offset_get) {
378: zval *rv;
379: SEPARATE_ARG_IF_REF(offset);
380: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
381: zval_ptr_dtor(&offset);
382: if (rv) {
383: zval_ptr_dtor(&intern->retval);
384: MAKE_STD_ZVAL(intern->retval);
385: ZVAL_ZVAL(intern->retval, rv, 1, 1);
386: return intern->retval;
387: }
388: return EG(uninitialized_zval_ptr);
389: }
390: }
391: ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
392:
393: /* When in a write context,
394: * ZE has to be fooled into thinking this is in a reference set
395: * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
396: if ((type == BP_VAR_W || type == BP_VAR_RW) && !Z_ISREF_PP(ret)) {
397: if (Z_REFCOUNT_PP(ret) > 1) {
398: zval *newval;
399:
400: /* Separate */
401: MAKE_STD_ZVAL(newval);
402: *newval = **ret;
403: zval_copy_ctor(newval);
404: Z_SET_REFCOUNT_P(newval, 1);
405:
406: /* Replace */
407: Z_DELREF_PP(ret);
408: *ret = newval;
409: }
410:
411: Z_SET_ISREF_PP(ret);
412: }
413:
414: return *ret;
415: } /* }}} */
416:
417: static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
418: {
419: return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
420: } /* }}} */
421:
422: static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
423: {
424: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
425: long index;
426: HashTable *ht;
427:
428: if (check_inherited && intern->fptr_offset_set) {
429: if (!offset) {
430: ALLOC_INIT_ZVAL(offset);
431: } else {
432: SEPARATE_ARG_IF_REF(offset);
433: }
434: zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
435: zval_ptr_dtor(&offset);
436: return;
437: }
438:
439: if (!offset) {
440: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
441: if (ht->nApplyCount > 0) {
442: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
443: return;
444: }
445: Z_ADDREF_P(value);
446: zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
447: return;
448: }
449: switch(Z_TYPE_P(offset)) {
450: case IS_STRING:
451: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
452: if (ht->nApplyCount > 0) {
453: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
454: return;
455: }
456: Z_ADDREF_P(value);
457: zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
458: return;
459: case IS_DOUBLE:
460: case IS_RESOURCE:
461: case IS_BOOL:
462: case IS_LONG:
463: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
464: if (ht->nApplyCount > 0) {
465: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
466: return;
467: }
468: if (offset->type == IS_DOUBLE) {
469: index = (long)Z_DVAL_P(offset);
470: } else {
471: index = Z_LVAL_P(offset);
472: }
473: Z_ADDREF_P(value);
474: zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
475: return;
476: case IS_NULL:
477: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
478: if (ht->nApplyCount > 0) {
479: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
480: return;
481: }
482: Z_ADDREF_P(value);
483: zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
484: return;
485: default:
486: zend_error(E_WARNING, "Illegal offset type");
487: return;
488: }
489: } /* }}} */
490:
491: static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
492: {
493: spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
494: } /* }}} */
495:
496: static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
497: {
498: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
499: long index;
500: HashTable *ht;
501:
502: if (check_inherited && intern->fptr_offset_del) {
503: SEPARATE_ARG_IF_REF(offset);
504: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
505: zval_ptr_dtor(&offset);
506: return;
507: }
508:
509: switch(Z_TYPE_P(offset)) {
510: case IS_STRING:
511: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
512: if (ht->nApplyCount > 0) {
513: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
514: return;
515: }
516: if (ht == &EG(symbol_table)) {
517: if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
518: zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
519: }
520: } else {
521: if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
522: zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
1.1.1.2 ! misho 523: } else {
! 524: spl_array_object *obj = intern;
! 525:
! 526: while (1) {
! 527: if ((obj->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
! 528: break;
! 529: } else if (Z_TYPE_P(obj->array) == IS_OBJECT) {
! 530: if ((obj->ar_flags & SPL_ARRAY_USE_OTHER) == 0) {
! 531: obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
! 532: break;
! 533: } else {
! 534: obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
! 535: }
! 536: } else {
! 537: obj = NULL;
! 538: break;
! 539: }
! 540: }
! 541: if (obj) {
! 542: zend_property_info *property_info = zend_get_property_info(obj->std.ce, offset, 1 TSRMLS_CC);
! 543:
! 544: if (property_info &&
! 545: (property_info->flags & ZEND_ACC_STATIC) == 0 &&
! 546: property_info->offset >= 0) {
! 547: obj->std.properties_table[property_info->offset] = NULL;
! 548: }
! 549: }
! 550: }
1.1 misho 551: }
552: break;
553: case IS_DOUBLE:
554: case IS_RESOURCE:
555: case IS_BOOL:
556: case IS_LONG:
557: if (offset->type == IS_DOUBLE) {
558: index = (long)Z_DVAL_P(offset);
559: } else {
560: index = Z_LVAL_P(offset);
561: }
562: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
563: if (ht->nApplyCount > 0) {
564: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
565: return;
566: }
567: if (zend_hash_index_del(ht, index) == FAILURE) {
568: zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
569: }
570: break;
571: default:
572: zend_error(E_WARNING, "Illegal offset type");
573: return;
574: }
575: spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
576: } /* }}} */
577:
578: static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
579: {
580: spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
581: } /* }}} */
582:
583: static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
584: {
585: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
586: long index;
587: zval *rv, **tmp;
588:
589: if (check_inherited && intern->fptr_offset_has) {
590: SEPARATE_ARG_IF_REF(offset);
591: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
592: zval_ptr_dtor(&offset);
593: if (rv && zend_is_true(rv)) {
594: zval_ptr_dtor(&rv);
595: return 1;
596: }
597: if (rv) {
598: zval_ptr_dtor(&rv);
599: }
600: return 0;
601: }
602:
603: switch(Z_TYPE_P(offset)) {
1.1.1.2 ! misho 604: case IS_STRING:
! 605: {
! 606: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
! 607: if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) {
! 608: switch (check_empty) {
! 609: case 0:
! 610: return Z_TYPE_PP(tmp) != IS_NULL;
! 611: case 2:
! 612: return 1;
! 613: default:
! 614: return zend_is_true(*tmp);
! 615: }
1.1 misho 616: }
617: }
618: return 0;
1.1.1.2 ! misho 619: case IS_DOUBLE:
! 620: case IS_RESOURCE:
! 621: case IS_BOOL:
! 622: case IS_LONG:
! 623: {
! 624: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
! 625: if (offset->type == IS_DOUBLE) {
! 626: index = (long)Z_DVAL_P(offset);
! 627: } else {
! 628: index = Z_LVAL_P(offset);
1.1 misho 629: }
1.1.1.2 ! misho 630: if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
! 631: switch (check_empty) {
! 632: case 0:
! 633: return Z_TYPE_PP(tmp) != IS_NULL;
! 634: case 2:
! 635: return 1;
! 636: default:
! 637: return zend_is_true(*tmp);
! 638: }
! 639: }
! 640: return 0;
1.1 misho 641: }
1.1.1.2 ! misho 642: default:
! 643: zend_error(E_WARNING, "Illegal offset type");
1.1 misho 644: }
645: return 0;
646: } /* }}} */
647:
648: static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
649: {
650: return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
651: } /* }}} */
652:
653: /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
654: proto bool ArrayIterator::offsetExists(mixed $index)
655: Returns whether the requested $index exists. */
656: SPL_METHOD(Array, offsetExists)
657: {
658: zval *index;
659: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
660: return;
661: }
1.1.1.2 ! misho 662: RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 2 TSRMLS_CC));
1.1 misho 663: } /* }}} */
664:
665: /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
666: proto mixed ArrayIterator::offsetGet(mixed $index)
667: Returns the value at the specified $index. */
668: SPL_METHOD(Array, offsetGet)
669: {
670: zval *index, *value;
671: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
672: return;
673: }
674: value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
675: RETURN_ZVAL(value, 1, 0);
676: } /* }}} */
677:
678: /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
679: proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
680: Sets the value at the specified $index to $newval. */
681: SPL_METHOD(Array, offsetSet)
682: {
683: zval *index, *value;
684: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
685: return;
686: }
687: spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
688: } /* }}} */
689:
690:
691: void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
692: {
693: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
694: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
695:
696: if (!aht) {
697: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
698: return;
699: }
700:
701: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
702: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
703: return;
704: }
705:
706: spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
707: if (!intern->pos) {
708: spl_array_set_pos(intern, aht->pListTail);
709: }
710: } /* }}} */
711:
712: /* {{{ proto void ArrayObject::append(mixed $newval)
713: proto void ArrayIterator::append(mixed $newval)
714: Appends the value (cannot be called for objects). */
715: SPL_METHOD(Array, append)
716: {
717: zval *value;
718:
719: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
720: return;
721: }
722: spl_array_iterator_append(getThis(), value TSRMLS_CC);
723: } /* }}} */
724:
725: /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
726: proto void ArrayIterator::offsetUnset(mixed $index)
727: Unsets the value at the specified $index. */
728: SPL_METHOD(Array, offsetUnset)
729: {
730: zval *index;
731: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
732: return;
733: }
734: spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
735: } /* }}} */
736:
737: /* {{{ proto array ArrayObject::getArrayCopy()
738: proto array ArrayIterator::getArrayCopy()
739: Return a copy of the contained array */
740: SPL_METHOD(Array, getArrayCopy)
741: {
742: zval *object = getThis(), *tmp;
743: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
744:
745: array_init(return_value);
746: zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
747: } /* }}} */
748:
749: static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
750: {
751: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
752: HashTable *result;
753:
754: if (intern->nApplyCount > 1) {
755: php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
756: }
757:
758: intern->nApplyCount++;
759: result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
760: intern->nApplyCount--;
761: return result;
762: } /* }}} */
763:
764: static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
765: {
766: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
767: zval *tmp, *storage;
768: int name_len;
769: char *zname;
770: zend_class_entry *base;
771:
772: *is_temp = 0;
773:
1.1.1.2 ! misho 774: if (!intern->std.properties) {
! 775: rebuild_object_properties(&intern->std);
! 776: }
! 777:
1.1 misho 778: if (HASH_OF(intern->array) == intern->std.properties) {
779: return intern->std.properties;
780: } else {
781: if (intern->debug_info == NULL) {
782: ALLOC_HASHTABLE(intern->debug_info);
783: ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
784: }
785:
786: if (intern->debug_info->nApplyCount == 0) {
787: zend_hash_clean(intern->debug_info);
788: zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
789:
790: storage = intern->array;
791: zval_add_ref(&storage);
792:
793: base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
794: zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
795: zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
796: efree(zname);
797: }
798:
799: return intern->debug_info;
800: }
801: }
802: /* }}} */
803:
1.1.1.2 ! misho 804: static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 805: {
806: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
807:
808: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 ! misho 809: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 810: return spl_array_read_dimension(object, member, type TSRMLS_CC);
811: }
1.1.1.2 ! misho 812: return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
1.1 misho 813: } /* }}} */
814:
1.1.1.2 ! misho 815: static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 816: {
817: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
818:
819: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 ! misho 820: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 821: spl_array_write_dimension(object, member, value TSRMLS_CC);
822: return;
823: }
1.1.1.2 ! misho 824: std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
1.1 misho 825: } /* }}} */
826:
1.1.1.2 ! misho 827: static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 828: {
829: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
830:
831: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 ! misho 832: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 833: return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC);
834: }
1.1.1.2 ! misho 835: return std_object_handlers.get_property_ptr_ptr(object, member, key TSRMLS_CC);
1.1 misho 836: } /* }}} */
837:
1.1.1.2 ! misho 838: static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 839: {
840: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
841:
842: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 ! misho 843: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 844: return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
845: }
1.1.1.2 ! misho 846: return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC);
1.1 misho 847: } /* }}} */
848:
1.1.1.2 ! misho 849: static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 850: {
851: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
852:
853: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 ! misho 854: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 855: spl_array_unset_dimension(object, member TSRMLS_CC);
856: spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
857: return;
858: }
1.1.1.2 ! misho 859: std_object_handlers.unset_property(object, member, key TSRMLS_CC);
! 860: } /* }}} */
! 861:
! 862: static int spl_array_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
! 863: {
! 864: HashTable *ht1,
! 865: *ht2;
! 866: spl_array_object *intern1,
! 867: *intern2;
! 868: int result = 0;
! 869: zval temp_zv;
! 870:
! 871: intern1 = (spl_array_object*)zend_object_store_get_object(o1 TSRMLS_CC);
! 872: intern2 = (spl_array_object*)zend_object_store_get_object(o2 TSRMLS_CC);
! 873: ht1 = spl_array_get_hash_table(intern1, 0 TSRMLS_CC);
! 874: ht2 = spl_array_get_hash_table(intern2, 0 TSRMLS_CC);
! 875:
! 876: zend_compare_symbol_tables(&temp_zv, ht1, ht2 TSRMLS_CC);
! 877: result = (int)Z_LVAL(temp_zv);
! 878: /* if we just compared std.properties, don't do it again */
! 879: if (result == 0 &&
! 880: !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
! 881: result = std_object_handlers.compare_objects(o1, o2 TSRMLS_CC);
! 882: }
! 883: return result;
1.1 misho 884: } /* }}} */
885:
886: static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
887: {
888: char *string_key;
889: uint string_length;
890: ulong num_key;
891:
892: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
893: do {
894: if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
895: if (!string_length || string_key[0]) {
896: return SUCCESS;
897: }
898: } else {
899: return SUCCESS;
900: }
901: if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
902: return FAILURE;
903: }
904: zend_hash_move_forward_ex(aht, &intern->pos);
905: spl_array_update_pos(intern);
906: } while (1);
907: }
908: return FAILURE;
909: } /* }}} */
910:
911: static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
912: {
913: zend_hash_move_forward_ex(aht, &intern->pos);
914: spl_array_update_pos(intern);
915: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
916: return spl_array_skip_protected(intern, aht TSRMLS_CC);
917: } else {
918: return zend_hash_has_more_elements_ex(aht, &intern->pos);
919: }
920: } /* }}} */
921:
922: static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
923: {
924: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
925: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
926: return FAILURE;
927: }
928:
929: return spl_array_next_no_verify(intern, aht TSRMLS_CC);
930: } /* }}} */
931:
932: static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
933: {
934: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
935:
936: return spl_array_next_ex(intern, aht TSRMLS_CC);
937:
938: } /* }}} */
939:
940: /* define an overloaded iterator structure */
941: typedef struct {
942: zend_user_iterator intern;
943: spl_array_object *object;
944: } spl_array_it;
945:
946: static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
947: {
948: spl_array_it *iterator = (spl_array_it *)iter;
949:
950: zend_user_it_invalidate_current(iter TSRMLS_CC);
951: zval_ptr_dtor((zval**)&iterator->intern.it.data);
952:
953: efree(iterator);
954: }
955: /* }}} */
956:
957: static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
958: {
959: spl_array_it *iterator = (spl_array_it *)iter;
960: spl_array_object *object = iterator->object;
961: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
962:
963: if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
964: return zend_user_it_valid(iter TSRMLS_CC);
965: } else {
966: if (!aht) {
967: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
968: return FAILURE;
969: }
970:
971: if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
972: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
973: return FAILURE;
974: } else {
975: return zend_hash_has_more_elements_ex(aht, &object->pos);
976: }
977: }
978: }
979: /* }}} */
980:
981: static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
982: {
983: spl_array_it *iterator = (spl_array_it *)iter;
984: spl_array_object *object = iterator->object;
985: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
986:
987: if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
988: zend_user_it_get_current_data(iter, data TSRMLS_CC);
989: } else {
990: if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
991: *data = NULL;
992: }
993: }
994: }
995: /* }}} */
996:
997: static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
998: {
999: spl_array_it *iterator = (spl_array_it *)iter;
1000: spl_array_object *object = iterator->object;
1001: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
1002:
1003: if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
1004: return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
1005: } else {
1006: if (!aht) {
1007: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
1008: return HASH_KEY_NON_EXISTANT;
1009: }
1010:
1011: if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
1012: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
1013: return HASH_KEY_NON_EXISTANT;
1014: }
1015:
1016: return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
1017: }
1018: }
1019: /* }}} */
1020:
1021: static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1022: {
1023: spl_array_it *iterator = (spl_array_it *)iter;
1024: spl_array_object *object = iterator->object;
1025: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
1026:
1027: if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
1028: zend_user_it_move_forward(iter TSRMLS_CC);
1029: } else {
1030: zend_user_it_invalidate_current(iter TSRMLS_CC);
1031: if (!aht) {
1032: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
1033: return;
1034: }
1035:
1036: if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
1037: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
1038: } else {
1039: spl_array_next_no_verify(object, aht TSRMLS_CC);
1040: }
1041: }
1042: }
1043: /* }}} */
1044:
1045: static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
1046: {
1047:
1048: zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
1049: spl_array_update_pos(intern);
1050: spl_array_skip_protected(intern, aht TSRMLS_CC);
1051:
1052: } /* }}} */
1053:
1054: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
1055: {
1056: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1057:
1058: if (!aht) {
1059: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
1060: return;
1061: }
1062:
1063: spl_array_rewind_ex(intern, aht TSRMLS_CC);
1064: }
1065: /* }}} */
1066:
1067: static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1068: {
1069: spl_array_it *iterator = (spl_array_it *)iter;
1070: spl_array_object *object = iterator->object;
1071:
1072: if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
1073: zend_user_it_rewind(iter TSRMLS_CC);
1074: } else {
1075: zend_user_it_invalidate_current(iter TSRMLS_CC);
1076: spl_array_rewind(object TSRMLS_CC);
1077: }
1078: }
1079: /* }}} */
1080:
1081: /* {{{ spl_array_set_array */
1082: static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
1083:
1084: if (Z_TYPE_PP(array) == IS_ARRAY) {
1085: SEPARATE_ZVAL_IF_NOT_REF(array);
1086: }
1087:
1088: if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
1089: zval_ptr_dtor(&intern->array);
1090: if (just_array) {
1091: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
1092: ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
1093: }
1094: ar_flags |= SPL_ARRAY_USE_OTHER;
1095: intern->array = *array;
1096: } else {
1097: if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
1098: zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
1099: return;
1100: }
1101: zval_ptr_dtor(&intern->array);
1102: intern->array = *array;
1103: }
1104: if (object == *array) {
1105: intern->ar_flags |= SPL_ARRAY_IS_SELF;
1106: intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
1107: } else {
1108: intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
1109: }
1110: intern->ar_flags |= ar_flags;
1111: Z_ADDREF_P(intern->array);
1112: if (Z_TYPE_PP(array) == IS_OBJECT) {
1113: zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
1114: if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
1115: || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
1116: zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name);
1117: }
1118: }
1119:
1120: spl_array_rewind(intern TSRMLS_CC);
1121: }
1122: /* }}} */
1123:
1124: /* iterator handler table */
1125: zend_object_iterator_funcs spl_array_it_funcs = {
1126: spl_array_it_dtor,
1127: spl_array_it_valid,
1128: spl_array_it_get_current_data,
1129: spl_array_it_get_current_key,
1130: spl_array_it_move_forward,
1131: spl_array_it_rewind
1132: };
1133:
1134: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
1135: {
1136: spl_array_it *iterator;
1137: spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1138:
1139: if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
1140: zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
1141: }
1142:
1143: iterator = emalloc(sizeof(spl_array_it));
1144:
1145: Z_ADDREF_P(object);
1146: iterator->intern.it.data = (void*)object;
1147: iterator->intern.it.funcs = &spl_array_it_funcs;
1148: iterator->intern.ce = ce;
1149: iterator->intern.value = NULL;
1150: iterator->object = array_object;
1151:
1152: return (zend_object_iterator*)iterator;
1153: }
1154: /* }}} */
1155:
1156: /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
1157: proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
1158: Constructs a new array iterator from a path. */
1159: SPL_METHOD(Array, __construct)
1160: {
1161: zval *object = getThis();
1162: spl_array_object *intern;
1163: zval **array;
1164: long ar_flags = 0;
1165: zend_class_entry *ce_get_iterator = spl_ce_Iterator;
1166: zend_error_handling error_handling;
1167:
1168: if (ZEND_NUM_ARGS() == 0) {
1169: return; /* nothing to do */
1170: }
1171:
1172: zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
1173:
1174: intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1175:
1176: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
1177: zend_restore_error_handling(&error_handling TSRMLS_CC);
1178: return;
1179: }
1180:
1181: if (ZEND_NUM_ARGS() > 2) {
1182: intern->ce_get_iterator = ce_get_iterator;
1183: }
1184:
1185: ar_flags &= ~SPL_ARRAY_INT_MASK;
1186:
1187: spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
1188:
1189: zend_restore_error_handling(&error_handling TSRMLS_CC);
1190:
1191: }
1192: /* }}} */
1193:
1194: /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
1195: Set the class used in getIterator. */
1196: SPL_METHOD(Array, setIteratorClass)
1197: {
1198: zval *object = getThis();
1199: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1200: zend_class_entry * ce_get_iterator = spl_ce_Iterator;
1201:
1202: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
1203: return;
1204: }
1205:
1206: intern->ce_get_iterator = ce_get_iterator;
1207: }
1208: /* }}} */
1209:
1210: /* {{{ proto string ArrayObject::getIteratorClass()
1211: Get the class used in getIterator. */
1212: SPL_METHOD(Array, getIteratorClass)
1213: {
1214: zval *object = getThis();
1215: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1216:
1217: if (zend_parse_parameters_none() == FAILURE) {
1218: return;
1219: }
1220:
1221: RETURN_STRING(intern->ce_get_iterator->name, 1);
1222: }
1223: /* }}} */
1224:
1225: /* {{{ proto int ArrayObject::getFlags()
1226: Get flags */
1227: SPL_METHOD(Array, getFlags)
1228: {
1229: zval *object = getThis();
1230: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1231:
1232: if (zend_parse_parameters_none() == FAILURE) {
1233: return;
1234: }
1235:
1236: RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
1237: }
1238: /* }}} */
1239:
1240: /* {{{ proto void ArrayObject::setFlags(int flags)
1241: Set flags */
1242: SPL_METHOD(Array, setFlags)
1243: {
1244: zval *object = getThis();
1245: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1246: long ar_flags = 0;
1247:
1248: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
1249: return;
1250: }
1251:
1252: intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
1253: }
1254: /* }}} */
1255:
1256: /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
1257: Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
1258: SPL_METHOD(Array, exchangeArray)
1259: {
1260: zval *object = getThis(), *tmp, **array;
1261: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1262:
1263: array_init(return_value);
1264: zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
1265:
1266: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
1267: return;
1268: }
1269:
1270: spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
1271:
1272: }
1273: /* }}} */
1274:
1275: /* {{{ proto ArrayIterator ArrayObject::getIterator()
1276: Create a new iterator from a ArrayObject instance */
1277: SPL_METHOD(Array, getIterator)
1278: {
1279: zval *object = getThis();
1280: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1281: spl_array_object *iterator;
1282: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1283:
1284: if (zend_parse_parameters_none() == FAILURE) {
1285: return;
1286: }
1287:
1288: if (!aht) {
1289: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1290: return;
1291: }
1292:
1293: return_value->type = IS_OBJECT;
1294: return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
1295: Z_SET_REFCOUNT_P(return_value, 1);
1296: Z_SET_ISREF_P(return_value);
1297: }
1298: /* }}} */
1299:
1300: /* {{{ proto void ArrayIterator::rewind()
1301: Rewind array back to the start */
1302: SPL_METHOD(Array, rewind)
1303: {
1304: zval *object = getThis();
1305: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1306:
1307: if (zend_parse_parameters_none() == FAILURE) {
1308: return;
1309: }
1310:
1311: spl_array_rewind(intern TSRMLS_CC);
1312: }
1313: /* }}} */
1314:
1315: /* {{{ proto void ArrayIterator::seek(int $position)
1316: Seek to position. */
1317: SPL_METHOD(Array, seek)
1318: {
1319: long opos, position;
1320: zval *object = getThis();
1321: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1322: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1323: int result;
1324:
1325: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
1326: return;
1327: }
1328:
1329: if (!aht) {
1330: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1331: return;
1332: }
1333:
1334: opos = position;
1335:
1336: if (position >= 0) { /* negative values are not supported */
1337: spl_array_rewind(intern TSRMLS_CC);
1338: result = SUCCESS;
1339:
1340: while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
1341:
1342: if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
1343: return; /* ok */
1344: }
1345: }
1346: zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
1347: } /* }}} */
1348:
1349: int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
1350: {
1351: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1352: HashPosition pos;
1353:
1354: if (!aht) {
1355: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1356: *count = 0;
1357: return FAILURE;
1358: }
1359:
1360: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
1361: /* We need to store the 'pos' since we'll modify it in the functions
1362: * we're going to call and which do not support 'pos' as parameter. */
1363: pos = intern->pos;
1364: *count = 0;
1365: spl_array_rewind(intern TSRMLS_CC);
1366: while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
1367: (*count)++;
1368: }
1369: spl_array_set_pos(intern, pos);
1370: return SUCCESS;
1371: } else {
1372: *count = zend_hash_num_elements(aht);
1373: return SUCCESS;
1374: }
1375: } /* }}} */
1376:
1377: int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1378: {
1379: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1380:
1381: if (intern->fptr_count) {
1382: zval *rv;
1383: zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
1384: if (rv) {
1385: zval_ptr_dtor(&intern->retval);
1386: MAKE_STD_ZVAL(intern->retval);
1387: ZVAL_ZVAL(intern->retval, rv, 1, 1);
1388: convert_to_long(intern->retval);
1389: *count = (long) Z_LVAL_P(intern->retval);
1390: return SUCCESS;
1391: }
1392: *count = 0;
1393: return FAILURE;
1394: }
1395: return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
1396: } /* }}} */
1397:
1398: /* {{{ proto int ArrayObject::count()
1399: proto int ArrayIterator::count()
1400: Return the number of elements in the Iterator. */
1401: SPL_METHOD(Array, count)
1402: {
1403: long count;
1404: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1405:
1406: if (zend_parse_parameters_none() == FAILURE) {
1407: return;
1408: }
1409:
1410: spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
1411:
1412: RETURN_LONG(count);
1413: } /* }}} */
1414:
1415: static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
1416: {
1417: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1418: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1419: zval *tmp, *arg;
1420: zval *retval_ptr = NULL;
1421:
1422: MAKE_STD_ZVAL(tmp);
1423: Z_TYPE_P(tmp) = IS_ARRAY;
1424: Z_ARRVAL_P(tmp) = aht;
1425:
1426: if (use_arg) {
1427: if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1428: Z_TYPE_P(tmp) = IS_NULL;
1429: zval_ptr_dtor(&tmp);
1430: zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
1431: return;
1432: }
1433: aht->nApplyCount++;
1434: zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
1435: aht->nApplyCount--;
1436: } else {
1437: aht->nApplyCount++;
1438: zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
1439: aht->nApplyCount--;
1440: }
1441: Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
1442: zval_ptr_dtor(&tmp);
1443: if (retval_ptr) {
1444: COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1445: }
1446: } /* }}} */
1447:
1448: #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
1449: SPL_METHOD(cname, fname) \
1450: { \
1451: spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
1452: }
1453:
1454: /* {{{ proto int ArrayObject::asort()
1455: proto int ArrayIterator::asort()
1456: Sort the entries by values. */
1457: SPL_ARRAY_METHOD(Array, asort, 0) /* }}} */
1458:
1459: /* {{{ proto int ArrayObject::ksort()
1460: proto int ArrayIterator::ksort()
1461: Sort the entries by key. */
1462: SPL_ARRAY_METHOD(Array, ksort, 0) /* }}} */
1463:
1464: /* {{{ proto int ArrayObject::uasort(callback cmp_function)
1465: proto int ArrayIterator::uasort(callback cmp_function)
1466: Sort the entries by values user defined function. */
1467: SPL_ARRAY_METHOD(Array, uasort, 1) /* }}} */
1468:
1469: /* {{{ proto int ArrayObject::uksort(callback cmp_function)
1470: proto int ArrayIterator::uksort(callback cmp_function)
1471: Sort the entries by key using user defined function. */
1472: SPL_ARRAY_METHOD(Array, uksort, 1) /* }}} */
1473:
1474: /* {{{ proto int ArrayObject::natsort()
1475: proto int ArrayIterator::natsort()
1476: Sort the entries by values using "natural order" algorithm. */
1477: SPL_ARRAY_METHOD(Array, natsort, 0) /* }}} */
1478:
1479: /* {{{ proto int ArrayObject::natcasesort()
1480: proto int ArrayIterator::natcasesort()
1481: Sort the entries by key using case insensitive "natural order" algorithm. */
1482: SPL_ARRAY_METHOD(Array, natcasesort, 0) /* }}} */
1483:
1484: /* {{{ proto mixed|NULL ArrayIterator::current()
1485: Return current array entry */
1486: SPL_METHOD(Array, current)
1487: {
1488: zval *object = getThis();
1489: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1490: zval **entry;
1491: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1492:
1493: if (zend_parse_parameters_none() == FAILURE) {
1494: return;
1495: }
1496:
1497: if (!aht) {
1498: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1499: return;
1500: }
1501:
1502: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
1503: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1504: return;
1505: }
1506:
1507: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1508: return;
1509: }
1510: RETVAL_ZVAL(*entry, 1, 0);
1511: }
1512: /* }}} */
1513:
1514: /* {{{ proto mixed|NULL ArrayIterator::key()
1515: Return current array key */
1516: SPL_METHOD(Array, key)
1517: {
1518: if (zend_parse_parameters_none() == FAILURE) {
1519: return;
1520: }
1521:
1522: spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
1523: } /* }}} */
1524:
1525: void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
1526: {
1527: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1528: char *string_key;
1529: uint string_length;
1530: ulong num_key;
1531: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1532:
1533: if (!aht) {
1534: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1535: return;
1536: }
1537:
1538: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
1539: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1540: return;
1541: }
1542:
1543: switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
1544: case HASH_KEY_IS_STRING:
1545: RETVAL_STRINGL(string_key, string_length - 1, 0);
1546: break;
1547: case HASH_KEY_IS_LONG:
1548: RETVAL_LONG(num_key);
1549: break;
1550: case HASH_KEY_NON_EXISTANT:
1551: return;
1552: }
1553: }
1554: /* }}} */
1555:
1556: /* {{{ proto void ArrayIterator::next()
1557: Move to next entry */
1558: SPL_METHOD(Array, next)
1559: {
1560: zval *object = getThis();
1561: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1562: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1563:
1564: if (zend_parse_parameters_none() == FAILURE) {
1565: return;
1566: }
1567:
1568: if (!aht) {
1569: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1570: return;
1571: }
1572:
1573: spl_array_next_ex(intern, aht TSRMLS_CC);
1574: }
1575: /* }}} */
1576:
1577: /* {{{ proto bool ArrayIterator::valid()
1578: Check whether array contains more entries */
1579: SPL_METHOD(Array, valid)
1580: {
1581: zval *object = getThis();
1582: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1583: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1584:
1585: if (zend_parse_parameters_none() == FAILURE) {
1586: return;
1587: }
1588:
1589: if (!aht) {
1590: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1591: return;
1592: }
1593:
1594: if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
1595: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1596: RETURN_FALSE;
1597: } else {
1598: RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
1599: }
1600: }
1601: /* }}} */
1602:
1603: /* {{{ proto bool RecursiveArrayIterator::hasChildren()
1604: Check whether current element has children (e.g. is an array) */
1605: SPL_METHOD(Array, hasChildren)
1606: {
1607: zval *object = getThis(), **entry;
1608: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1609: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1610:
1611: if (zend_parse_parameters_none() == FAILURE) {
1612: return;
1613: }
1614:
1615: if (!aht) {
1616: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1617: RETURN_FALSE;
1618: }
1619:
1620: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
1621: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1622: RETURN_FALSE;
1623: }
1624:
1625: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1626: RETURN_FALSE;
1627: }
1628:
1629: RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
1630: }
1631: /* }}} */
1632:
1633: /* {{{ proto object RecursiveArrayIterator::getChildren()
1634: Create a sub iterator for the current element (same class as $this) */
1635: SPL_METHOD(Array, getChildren)
1636: {
1637: zval *object = getThis(), **entry, *flags;
1638: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1639: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1640:
1641: if (zend_parse_parameters_none() == FAILURE) {
1642: return;
1643: }
1644:
1645: if (!aht) {
1646: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1647: return;
1648: }
1649:
1650: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
1651: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1652: return;
1653: }
1654:
1655: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1656: return;
1657: }
1658:
1659: if (Z_TYPE_PP(entry) == IS_OBJECT) {
1660: if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
1661: return;
1662: }
1663: if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
1664: RETURN_ZVAL(*entry, 0, 0);
1665: }
1666: }
1667:
1668: MAKE_STD_ZVAL(flags);
1669: ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
1670: spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
1671: zval_ptr_dtor(&flags);
1672: }
1673: /* }}} */
1674:
1.1.1.2 ! misho 1675: /* {{{ proto string ArrayObject::serialize()
! 1676: Serialize the object */
! 1677: SPL_METHOD(Array, serialize)
! 1678: {
! 1679: zval *object = getThis();
! 1680: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1.1 misho 1681: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1682: zval members, *pmembers;
1.1.1.2 ! misho 1683: php_serialize_data_t var_hash;
1.1 misho 1684: smart_str buf = {0};
1685: zval *flags;
1686:
1.1.1.2 ! misho 1687: if (zend_parse_parameters_none() == FAILURE) {
! 1688: return;
! 1689: }
! 1690:
1.1 misho 1691: if (!aht) {
1692: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1.1.1.2 ! misho 1693: return;
1.1 misho 1694: }
1695:
1.1.1.2 ! misho 1696: PHP_VAR_SERIALIZE_INIT(var_hash);
! 1697:
1.1 misho 1698: MAKE_STD_ZVAL(flags);
1699: ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
1700:
1701: /* storage */
1702: smart_str_appendl(&buf, "x:", 2);
1.1.1.2 ! misho 1703: php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
1.1 misho 1704: zval_ptr_dtor(&flags);
1705:
1706: if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
1.1.1.2 ! misho 1707: php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC);
1.1 misho 1708: smart_str_appendc(&buf, ';');
1709: }
1710:
1711: /* members */
1712: smart_str_appendl(&buf, "m:", 2);
1713: INIT_PZVAL(&members);
1.1.1.2 ! misho 1714: if (!intern->std.properties) {
! 1715: rebuild_object_properties(&intern->std);
! 1716: }
1.1 misho 1717: Z_ARRVAL(members) = intern->std.properties;
1718: Z_TYPE(members) = IS_ARRAY;
1719: pmembers = &members;
1.1.1.2 ! misho 1720: php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
1.1 misho 1721:
1722: /* done */
1.1.1.2 ! misho 1723: PHP_VAR_SERIALIZE_DESTROY(var_hash);
1.1 misho 1724:
1725: if (buf.c) {
1726: RETURN_STRINGL(buf.c, buf.len, 0);
1727: }
1728:
1729: RETURN_NULL();
1730: } /* }}} */
1731:
1.1.1.2 ! misho 1732: /* {{{ proto void ArrayObject::unserialize(string serialized)
! 1733: * unserialize the object
! 1734: */
! 1735: SPL_METHOD(Array, unserialize)
1.1 misho 1736: {
1.1.1.2 ! misho 1737: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1.1 misho 1738:
1.1.1.2 ! misho 1739: char *buf;
! 1740: int buf_len;
1.1 misho 1741: const unsigned char *p, *s;
1.1.1.2 ! misho 1742: php_unserialize_data_t var_hash;
1.1 misho 1743: zval *pmembers, *pflags = NULL;
1744: long flags;
1.1.1.2 ! misho 1745:
! 1746: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
! 1747: return;
! 1748: }
! 1749:
! 1750: if (buf_len == 0) {
! 1751: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
! 1752: return;
! 1753: }
1.1 misho 1754:
1755: /* storage */
1.1.1.2 ! misho 1756: s = p = (const unsigned char*)buf;
! 1757: PHP_VAR_UNSERIALIZE_INIT(var_hash);
1.1 misho 1758:
1759: if (*p!= 'x' || *++p != ':') {
1760: goto outexcept;
1761: }
1762: ++p;
1763:
1764: ALLOC_INIT_ZVAL(pflags);
1.1.1.2 ! misho 1765: if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
1.1 misho 1766: zval_ptr_dtor(&pflags);
1767: goto outexcept;
1768: }
1769:
1770: --p; /* for ';' */
1771: flags = Z_LVAL_P(pflags);
1772: zval_ptr_dtor(&pflags);
1773: /* flags needs to be verified and we also need to verify whether the next
1774: * thing we get is ';'. After that we require an 'm' or somethign else
1775: * where 'm' stands for members and anything else should be an array. If
1776: * neither 'a' or 'm' follows we have an error. */
1777:
1778: if (*p != ';') {
1779: goto outexcept;
1780: }
1781: ++p;
1782:
1783: if (*p!='m') {
1784: if (*p!='a' && *p!='O' && *p!='C') {
1785: goto outexcept;
1786: }
1787: intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
1788: intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1789: zval_ptr_dtor(&intern->array);
1790: ALLOC_INIT_ZVAL(intern->array);
1.1.1.2 ! misho 1791: if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)) {
1.1 misho 1792: goto outexcept;
1793: }
1794: }
1795: if (*p != ';') {
1796: goto outexcept;
1797: }
1798: ++p;
1799:
1800: /* members */
1801: if (*p!= 'm' || *++p != ':') {
1802: goto outexcept;
1803: }
1804: ++p;
1805:
1806: ALLOC_INIT_ZVAL(pmembers);
1.1.1.2 ! misho 1807: if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
1.1 misho 1808: zval_ptr_dtor(&pmembers);
1809: goto outexcept;
1810: }
1811:
1812: /* copy members */
1.1.1.2 ! misho 1813: if (!intern->std.properties) {
! 1814: rebuild_object_properties(&intern->std);
! 1815: }
1.1 misho 1816: zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
1817: zval_ptr_dtor(&pmembers);
1818:
1819: /* done reading $serialized */
1.1.1.2 ! misho 1820:
! 1821: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1.1 misho 1822: return;
1823:
1824: outexcept:
1.1.1.2 ! misho 1825: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
! 1826: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
1.1 misho 1827: return;
1828:
1829: } /* }}} */
1830:
1831: /* {{{ arginfo and function tbale */
1832: ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
1833: ZEND_ARG_INFO(0, array)
1834: ZEND_END_ARG_INFO()
1835:
1836: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
1837: ZEND_ARG_INFO(0, index)
1838: ZEND_END_ARG_INFO()
1839:
1840: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
1841: ZEND_ARG_INFO(0, index)
1842: ZEND_ARG_INFO(0, newval)
1843: ZEND_END_ARG_INFO()
1844:
1845: ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
1846: ZEND_ARG_INFO(0, value)
1847: ZEND_END_ARG_INFO()
1848:
1849: ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
1850: ZEND_ARG_INFO(0, position)
1851: ZEND_END_ARG_INFO()
1852:
1853: ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
1854: ZEND_ARG_INFO(0, array)
1855: ZEND_END_ARG_INFO()
1856:
1857: ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
1858: ZEND_ARG_INFO(0, flags)
1859: ZEND_END_ARG_INFO()
1860:
1861: ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
1862: ZEND_ARG_INFO(0, iteratorClass)
1863: ZEND_END_ARG_INFO()
1864:
1865: ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
1866: ZEND_ARG_INFO(0, cmp_function)
1867: ZEND_END_ARG_INFO();
1868:
1869: ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
1870: ZEND_ARG_INFO(0, serialized)
1871: ZEND_END_ARG_INFO();
1872:
1873: ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
1874: ZEND_END_ARG_INFO()
1875:
1876: static const zend_function_entry spl_funcs_ArrayObject[] = {
1877: SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1878: SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1879: SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1880: SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1881: SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1882: SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1883: SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
1884: SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
1885: SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
1886: SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1887: SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
1888: SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
1889: SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1890: SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1891: SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
1892: SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
1893: SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
1894: SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
1895: /* ArrayObject specific */
1896: SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC)
1897: SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
1898: SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
1899: SPL_ME(Array, getIteratorClass, arginfo_array_void, ZEND_ACC_PUBLIC)
1900: PHP_FE_END
1901: };
1902:
1903: static const zend_function_entry spl_funcs_ArrayIterator[] = {
1904: SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1905: SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1906: SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1907: SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1908: SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1909: SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1910: SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
1911: SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
1912: SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
1913: SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1914: SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
1915: SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
1916: SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1917: SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1918: SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
1919: SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
1920: SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
1921: SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
1922: /* ArrayIterator specific */
1923: SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC)
1924: SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC)
1925: SPL_ME(Array, key, arginfo_array_void, ZEND_ACC_PUBLIC)
1926: SPL_ME(Array, next, arginfo_array_void, ZEND_ACC_PUBLIC)
1927: SPL_ME(Array, valid, arginfo_array_void, ZEND_ACC_PUBLIC)
1928: SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
1929: PHP_FE_END
1930: };
1931:
1932: static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
1933: SPL_ME(Array, hasChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
1934: SPL_ME(Array, getChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
1935: PHP_FE_END
1936: };
1937: /* }}} */
1938:
1939: /* {{{ PHP_MINIT_FUNCTION(spl_array) */
1940: PHP_MINIT_FUNCTION(spl_array)
1941: {
1942: REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
1943: REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
1944: REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
1945: REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
1946: memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1947:
1948: spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
1949: spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
1950: spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
1951: spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
1952: spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
1953: spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
1954:
1955: spl_handler_ArrayObject.get_properties = spl_array_get_properties;
1956: spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
1957: spl_handler_ArrayObject.read_property = spl_array_read_property;
1958: spl_handler_ArrayObject.write_property = spl_array_write_property;
1959: spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
1960: spl_handler_ArrayObject.has_property = spl_array_has_property;
1961: spl_handler_ArrayObject.unset_property = spl_array_unset_property;
1962:
1.1.1.2 ! misho 1963: spl_handler_ArrayObject.compare_objects = spl_array_compare_objects;
! 1964:
1.1 misho 1965: REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
1966: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
1967: REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
1968: REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
1969: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
1970: memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
1971: spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
1972:
1973: REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
1974: REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
1975: spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
1976:
1977: REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
1978: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
1979:
1980: REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1981: REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1982:
1983: REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1984: REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1985:
1986: REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
1987:
1988: return SUCCESS;
1989: }
1990: /* }}} */
1991:
1992: /*
1993: * Local variables:
1994: * tab-width: 4
1995: * c-basic-offset: 4
1996: * End:
1997: * vim600: fdm=marker
1998: * vim: noet sw=4 ts=4
1999: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>