1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 :
19 : /* $Id: spl_array.c 280904 2009-05-21 13:26:29Z lbarnaud $ */
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 "zend_interfaces.h"
29 : #include "zend_exceptions.h"
30 :
31 : #include "php_spl.h"
32 : #include "spl_functions.h"
33 : #include "spl_engine.h"
34 : #include "spl_iterators.h"
35 : #include "spl_array.h"
36 : #include "spl_exceptions.h"
37 :
38 : zend_object_handlers spl_handler_ArrayObject;
39 : PHPAPI zend_class_entry *spl_ce_ArrayObject;
40 :
41 : zend_object_handlers spl_handler_ArrayIterator;
42 : PHPAPI zend_class_entry *spl_ce_ArrayIterator;
43 : PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
44 :
45 : #define SPL_ARRAY_STD_PROP_LIST 0x00000001
46 : #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
47 : #define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
48 : #define SPL_ARRAY_OVERLOADED_VALID 0x00020000
49 : #define SPL_ARRAY_OVERLOADED_KEY 0x00040000
50 : #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
51 : #define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
52 : #define SPL_ARRAY_IS_REF 0x01000000
53 : #define SPL_ARRAY_IS_SELF 0x02000000
54 : #define SPL_ARRAY_USE_OTHER 0x04000000
55 : #define SPL_ARRAY_INT_MASK 0xFFFF0000
56 : #define SPL_ARRAY_CLONE_MASK 0x03000007
57 :
58 : typedef struct _spl_array_object {
59 : zend_object std;
60 : zval *array;
61 : zval *retval;
62 : HashPosition pos;
63 : int ar_flags;
64 : int is_self;
65 : zend_function * fptr_offset_get;
66 : zend_function * fptr_offset_set;
67 : zend_function * fptr_offset_has;
68 : zend_function * fptr_offset_del;
69 : zend_class_entry* ce_get_iterator;
70 : } spl_array_object;
71 :
72 12984 : static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) {
73 12984 : if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
74 136 : return intern->std.properties;
75 12848 : } 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) {
76 2314 : spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
77 2314 : return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
78 10534 : } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
79 16 : return intern->std.properties;
80 : } else {
81 10518 : return HASH_OF(intern->array);
82 : }
83 : }
84 :
85 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
86 :
87 : SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
88 722 : {
89 722 : HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
90 : Bucket *p;
91 :
92 : /* IS_CONSISTENT(ht);*/
93 :
94 : /* HASH_PROTECT_RECURSION(ht);*/
95 722 : p = ht->pListHead;
96 2185 : while (p != NULL) {
97 1430 : if (p == intern->pos) {
98 689 : return SUCCESS;
99 : }
100 741 : p = p->pListNext;
101 : }
102 : /* HASH_UNPROTECT_RECURSION(ht); */
103 33 : spl_array_rewind(intern TSRMLS_CC);
104 33 : return FAILURE;
105 : }
106 : /* }}} */
107 :
108 : /* {{{ spl_array_object_free_storage */
109 : static void spl_array_object_free_storage(void *object TSRMLS_DC)
110 491 : {
111 491 : spl_array_object *intern = (spl_array_object *)object;
112 :
113 491 : zend_object_std_dtor(&intern->std TSRMLS_CC);
114 :
115 491 : zval_ptr_dtor(&intern->array);
116 491 : zval_ptr_dtor(&intern->retval);
117 :
118 491 : efree(object);
119 491 : }
120 : /* }}} */
121 :
122 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
123 :
124 : /* {{{ spl_array_object_new */
125 : 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)
126 491 : {
127 : zend_object_value retval;
128 : spl_array_object *intern;
129 : zval *tmp;
130 491 : zend_class_entry * parent = class_type;
131 491 : int inherited = 0;
132 :
133 491 : intern = emalloc(sizeof(spl_array_object));
134 491 : memset(intern, 0, sizeof(spl_array_object));
135 491 : *obj = intern;
136 491 : ALLOC_INIT_ZVAL(intern->retval);
137 :
138 491 : zend_object_std_init(&intern->std, class_type TSRMLS_CC);
139 491 : zend_hash_copy(intern->std.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
140 :
141 491 : intern->ar_flags = 0;
142 491 : intern->ce_get_iterator = spl_ce_ArrayIterator;
143 491 : if (orig) {
144 73 : spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
145 :
146 73 : intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
147 73 : intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
148 73 : intern->ce_get_iterator = other->ce_get_iterator;
149 73 : if (clone_orig) {
150 8 : intern->array = other->array;
151 8 : if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
152 6 : MAKE_STD_ZVAL(intern->array);
153 6 : array_init(intern->array);
154 6 : zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
155 : }
156 8 : if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
157 2 : ZVAL_ADDREF(other->array);
158 : }
159 : } else {
160 65 : intern->array = orig;
161 65 : ZVAL_ADDREF(intern->array);
162 65 : intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
163 : }
164 : } else {
165 418 : MAKE_STD_ZVAL(intern->array);
166 418 : array_init(intern->array);
167 418 : intern->ar_flags &= ~SPL_ARRAY_IS_REF;
168 : }
169 :
170 491 : 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);
171 1098 : while (parent) {
172 607 : if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
173 368 : retval.handlers = &spl_handler_ArrayIterator;
174 368 : class_type->get_iterator = spl_array_get_iterator;
175 368 : break;
176 239 : } else if (parent == spl_ce_ArrayObject) {
177 123 : retval.handlers = &spl_handler_ArrayObject;
178 123 : break;
179 : }
180 116 : parent = parent->parent;
181 116 : inherited = 1;
182 : }
183 491 : if (!parent) { /* this must never happen */
184 0 : php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
185 : }
186 491 : if (inherited) {
187 116 : zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
188 116 : if (intern->fptr_offset_get->common.scope == parent) {
189 85 : intern->fptr_offset_get = NULL;
190 : }
191 116 : zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
192 116 : if (intern->fptr_offset_set->common.scope == parent) {
193 85 : intern->fptr_offset_set = NULL;
194 : }
195 116 : zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
196 116 : if (intern->fptr_offset_has->common.scope == parent) {
197 88 : intern->fptr_offset_has = NULL;
198 : }
199 116 : zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
200 116 : if (intern->fptr_offset_del->common.scope == parent) {
201 88 : intern->fptr_offset_del = NULL;
202 : }
203 : }
204 : /* Cache iterator functions if ArrayIterator or derived. Check current's */
205 : /* cache since only current is always required */
206 491 : if (retval.handlers == &spl_handler_ArrayIterator) {
207 368 : if (!class_type->iterator_funcs.zf_current) {
208 132 : zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
209 132 : zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
210 132 : zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
211 132 : zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
212 132 : zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
213 : }
214 368 : if (inherited) {
215 89 : if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
216 89 : if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
217 89 : if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
218 89 : if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
219 89 : if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
220 : }
221 : }
222 :
223 491 : spl_array_rewind(intern TSRMLS_CC);
224 491 : return retval;
225 : }
226 : /* }}} */
227 :
228 : /* {{{ spl_array_object_new */
229 : static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
230 418 : {
231 : spl_array_object *tmp;
232 418 : return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
233 : }
234 : /* }}} */
235 :
236 : /* {{{ spl_array_object_clone */
237 : static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
238 8 : {
239 : zend_object_value new_obj_val;
240 : zend_object *old_object;
241 : zend_object *new_object;
242 8 : zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
243 : spl_array_object *intern;
244 :
245 8 : old_object = zend_objects_get_address(zobject TSRMLS_CC);
246 8 : new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
247 8 : new_object = &intern->std;
248 :
249 8 : zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
250 :
251 8 : return new_obj_val;
252 : }
253 : /* }}} */
254 :
255 : static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
256 95 : {
257 95 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
258 : zval **retval;
259 : long index;
260 95 : HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
261 :
262 : /* We cannot get the pointer pointer so we don't allow it here for now
263 : if (check_inherited && intern->fptr_offset_get) {
264 : return zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", NULL, offset);
265 : }*/
266 :
267 95 : if (!offset) {
268 1 : return &EG(uninitialized_zval_ptr);
269 : }
270 :
271 94 : switch(Z_TYPE_P(offset)) {
272 : case IS_STRING:
273 65 : if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
274 23 : if (type == BP_VAR_W || type == BP_VAR_RW) {
275 : zval *value;
276 1 : ALLOC_INIT_ZVAL(value);
277 1 : zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
278 1 : zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval);
279 1 : return retval;
280 : } else {
281 22 : zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset));
282 22 : return &EG(uninitialized_zval_ptr);
283 : }
284 : } else {
285 42 : return retval;
286 : }
287 : case IS_DOUBLE:
288 : case IS_RESOURCE:
289 : case IS_BOOL:
290 : case IS_LONG:
291 29 : if (offset->type == IS_DOUBLE) {
292 0 : index = (long)Z_DVAL_P(offset);
293 : } else {
294 29 : index = Z_LVAL_P(offset);
295 : }
296 29 : if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
297 2 : if (type == BP_VAR_W || type == BP_VAR_RW) {
298 : zval *value;
299 0 : ALLOC_INIT_ZVAL(value);
300 0 : zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
301 0 : zend_hash_index_find(ht, index, (void **) &retval);
302 0 : return retval;
303 : } else {
304 2 : zend_error(E_NOTICE, "Undefined offset: %ld", Z_LVAL_P(offset));
305 2 : return &EG(uninitialized_zval_ptr);
306 : }
307 : } else {
308 27 : return retval;
309 : }
310 : break;
311 : default:
312 0 : zend_error(E_WARNING, "Illegal offset type");
313 0 : return &EG(uninitialized_zval_ptr);
314 : }
315 : } /* }}} */
316 :
317 : static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
318 101 : {
319 : zval **ret;
320 :
321 101 : if (check_inherited) {
322 95 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
323 95 : if (intern->fptr_offset_get) {
324 : zval *rv;
325 6 : SEPARATE_ARG_IF_REF(offset);
326 6 : zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
327 6 : zval_ptr_dtor(&offset);
328 6 : if (rv) {
329 5 : zval_ptr_dtor(&intern->retval);
330 5 : MAKE_STD_ZVAL(intern->retval);
331 5 : ZVAL_ZVAL(intern->retval, rv, 1, 1);
332 5 : return intern->retval;
333 : }
334 1 : return EG(uninitialized_zval_ptr);
335 : }
336 : }
337 95 : ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
338 :
339 : /* When in a write context,
340 : * ZE has to be fooled into thinking this is in a reference set
341 : * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
342 95 : if ((type == BP_VAR_W || type == BP_VAR_RW) && !(*ret)->is_ref) {
343 3 : if ((*ret)->refcount > 1) {
344 : zval *newval;
345 :
346 : /* Separate */
347 1 : MAKE_STD_ZVAL(newval);
348 1 : *newval = **ret;
349 1 : zval_copy_ctor(newval);
350 1 : newval->refcount = 1;
351 :
352 : /* Replace */
353 1 : (*ret)->refcount--;
354 1 : *ret = newval;
355 : }
356 :
357 3 : (*ret)->is_ref = 1;
358 : }
359 :
360 95 : return *ret;
361 : } /* }}} */
362 :
363 : static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
364 95 : {
365 95 : return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
366 : } /* }}} */
367 :
368 : static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
369 120 : {
370 120 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
371 : long index;
372 :
373 120 : if (check_inherited && intern->fptr_offset_set) {
374 6 : if (!offset) {
375 4 : ALLOC_INIT_ZVAL(offset);
376 : } else {
377 2 : SEPARATE_ARG_IF_REF(offset);
378 : }
379 6 : zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
380 6 : zval_ptr_dtor(&offset);
381 6 : return;
382 : }
383 :
384 114 : if (!offset) {
385 37 : value->refcount++;
386 37 : zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
387 37 : return;
388 : }
389 77 : switch(Z_TYPE_P(offset)) {
390 : case IS_STRING:
391 53 : if (*Z_STRVAL_P(offset) == '\0') {
392 2 : zend_throw_exception(spl_ce_InvalidArgumentException, "An offset must not begin with \\0 or be empty", 0 TSRMLS_CC);
393 2 : return;
394 : }
395 51 : value->refcount++;
396 51 : zend_symtable_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
397 51 : return;
398 : case IS_DOUBLE:
399 : case IS_RESOURCE:
400 : case IS_BOOL:
401 : case IS_LONG:
402 20 : if (offset->type == IS_DOUBLE) {
403 0 : index = (long)Z_DVAL_P(offset);
404 : } else {
405 20 : index = Z_LVAL_P(offset);
406 : }
407 20 : value->refcount++;
408 20 : zend_hash_index_update(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index, (void**)&value, sizeof(void*), NULL);
409 20 : return;
410 : case IS_NULL:
411 4 : value->refcount++;
412 4 : zend_hash_next_index_insert(spl_array_get_hash_table(intern, 0 TSRMLS_CC), (void**)&value, sizeof(void*), NULL);
413 4 : return;
414 : default:
415 0 : zend_error(E_WARNING, "Illegal offset type");
416 0 : return;
417 : }
418 : } /* }}} */
419 :
420 : static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
421 103 : {
422 103 : spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
423 103 : } /* }}} */
424 :
425 : static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
426 47 : {
427 47 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
428 : long index;
429 :
430 47 : if (check_inherited && intern->fptr_offset_del) {
431 0 : SEPARATE_ARG_IF_REF(offset);
432 0 : zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
433 0 : zval_ptr_dtor(&offset);
434 0 : return;
435 : }
436 :
437 47 : switch(Z_TYPE_P(offset)) {
438 : case IS_STRING:
439 33 : if (spl_array_get_hash_table(intern, 0 TSRMLS_CC) == &EG(symbol_table)) {
440 1 : if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
441 0 : zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
442 : }
443 : } else {
444 32 : if (zend_symtable_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
445 9 : zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
446 : }
447 : }
448 33 : break;
449 : case IS_DOUBLE:
450 : case IS_RESOURCE:
451 : case IS_BOOL:
452 : case IS_LONG:
453 14 : if (offset->type == IS_DOUBLE) {
454 0 : index = (long)Z_DVAL_P(offset);
455 : } else {
456 14 : index = Z_LVAL_P(offset);
457 : }
458 14 : if (zend_hash_index_del(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index) == FAILURE) {
459 2 : zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
460 : }
461 14 : break;
462 : default:
463 0 : zend_error(E_WARNING, "Illegal offset type");
464 0 : return;
465 : }
466 47 : spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
467 : } /* }}} */
468 :
469 : static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
470 39 : {
471 39 : spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
472 39 : } /* }}} */
473 :
474 : static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
475 56 : {
476 56 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
477 : long index;
478 : zval *rv, **tmp;
479 :
480 56 : if (check_inherited && intern->fptr_offset_has) {
481 0 : SEPARATE_ARG_IF_REF(offset);
482 0 : zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
483 0 : zval_ptr_dtor(&offset);
484 0 : if (rv && zend_is_true(rv)) {
485 0 : zval_ptr_dtor(&rv);
486 0 : return 1;
487 : }
488 0 : if (rv) {
489 0 : zval_ptr_dtor(&rv);
490 : }
491 0 : return 0;
492 : }
493 :
494 56 : switch(Z_TYPE_P(offset)) {
495 : case IS_STRING:
496 47 : if (check_empty) {
497 5 : if (zend_symtable_find(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE && zend_is_true(*tmp)) {
498 1 : return 1;
499 : }
500 4 : return 0;
501 : } else {
502 42 : return zend_symtable_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1);
503 : }
504 : case IS_DOUBLE:
505 : case IS_RESOURCE:
506 : case IS_BOOL:
507 : case IS_LONG:
508 9 : if (offset->type == IS_DOUBLE) {
509 0 : index = (long)Z_DVAL_P(offset);
510 : } else {
511 9 : index = Z_LVAL_P(offset);
512 : }
513 9 : if (check_empty) {
514 4 : HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
515 4 : if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE && zend_is_true(*tmp)) {
516 3 : return 1;
517 : }
518 1 : return 0;
519 : } else {
520 5 : return zend_hash_index_exists(spl_array_get_hash_table(intern, 0 TSRMLS_CC), index);
521 : }
522 : default:
523 0 : zend_error(E_WARNING, "Illegal offset type");
524 : }
525 0 : return 0;
526 : } /* }}} */
527 :
528 : static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
529 51 : {
530 51 : return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
531 : } /* }}} */
532 :
533 : /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
534 : proto bool ArrayIterator::offsetExists(mixed $index)
535 : Returns whether the requested $index exists. */
536 : SPL_METHOD(Array, offsetExists)
537 5 : {
538 : zval *index;
539 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
540 0 : return;
541 : }
542 5 : RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 0 TSRMLS_CC));
543 : } /* }}} */
544 :
545 : /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
546 : proto mixed ArrayIterator::offsetGet(mixed $index)
547 : Returns the value at the specified $index. */
548 : SPL_METHOD(Array, offsetGet)
549 6 : {
550 : zval *index, *value;
551 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
552 0 : return;
553 : }
554 6 : value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
555 6 : RETURN_ZVAL(value, 1, 0);
556 : } /* }}} */
557 :
558 : /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
559 : proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
560 : Sets the value at the specified $index to $newval. */
561 : SPL_METHOD(Array, offsetSet)
562 17 : {
563 : zval *index, *value;
564 17 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
565 0 : return;
566 : }
567 17 : spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
568 : } /* }}} */
569 :
570 :
571 : void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
572 21 : {
573 21 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
574 21 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
575 :
576 21 : if (!aht) {
577 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
578 0 : return;
579 : }
580 :
581 21 : if (Z_TYPE_P(intern->array) == IS_OBJECT) {
582 1 : php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
583 0 : return;
584 : }
585 :
586 20 : spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
587 20 : if (!intern->pos) {
588 10 : intern->pos = aht->pListTail;
589 : }
590 : } /* }}} */
591 :
592 : /* {{{ proto void ArrayObject::append(mixed $newval)
593 : proto void ArrayIterator::append(mixed $newval)
594 : Appends the value (cannot be called for objects). */
595 : SPL_METHOD(Array, append)
596 9 : {
597 : zval *value;
598 :
599 9 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
600 0 : return;
601 : }
602 9 : spl_array_iterator_append(getThis(), value TSRMLS_CC);
603 : } /* }}} */
604 :
605 : /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
606 : proto void ArrayIterator::offsetUnset(mixed $index)
607 : Unsets the value at the specified $index. */
608 : SPL_METHOD(Array, offsetUnset)
609 8 : {
610 : zval *index;
611 8 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
612 0 : return;
613 : }
614 8 : spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
615 : } /* }}} */
616 :
617 : /* {{ proto array ArrayObject::getArrayCopy()
618 : proto array ArrayIterator::getArrayCopy()
619 : Return a copy of the contained array */
620 : SPL_METHOD(Array, getArrayCopy)
621 11 : {
622 11 : zval *object = getThis(), *tmp;
623 11 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
624 :
625 11 : array_init(return_value);
626 11 : 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*));
627 11 : } /* }}} */
628 :
629 : static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
630 139 : {
631 139 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
632 :
633 139 : return spl_array_get_hash_table(intern, 1 TSRMLS_CC);
634 : } /* }}} */
635 :
636 : static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
637 73 : {
638 73 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
639 :
640 73 : if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
641 : && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
642 25 : return spl_array_read_dimension(object, member, type TSRMLS_CC);
643 : }
644 48 : return std_object_handlers.read_property(object, member, type TSRMLS_CC);
645 : } /* }}} */
646 :
647 : static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
648 75 : {
649 75 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
650 :
651 75 : if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
652 : && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
653 15 : spl_array_write_dimension(object, member, value TSRMLS_CC);
654 15 : return;
655 : }
656 60 : std_object_handlers.write_property(object, member, value TSRMLS_CC);
657 : } /* }}} */
658 :
659 : static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
660 0 : {
661 0 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
662 :
663 0 : if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
664 : && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
665 0 : return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC);
666 : }
667 0 : return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC);
668 : } /* }}} */
669 :
670 : static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
671 44 : {
672 44 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
673 :
674 44 : if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
675 : && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
676 22 : return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
677 : }
678 22 : return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC);
679 :
680 : } /* }}} */
681 :
682 : static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
683 25 : {
684 25 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
685 :
686 25 : if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
687 : && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) {
688 11 : spl_array_unset_dimension(object, member TSRMLS_CC);
689 11 : spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
690 11 : return;
691 : }
692 14 : std_object_handlers.unset_property(object, member TSRMLS_CC);
693 : } /* }}} */
694 :
695 : static int spl_array_skip_protected(spl_array_object *intern TSRMLS_DC) /* {{{ */
696 1530 : {
697 : char *string_key;
698 : uint string_length;
699 : ulong num_key;
700 1530 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
701 :
702 1530 : if (Z_TYPE_P(intern->array) == IS_OBJECT) {
703 : do {
704 477 : if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
705 177 : if (!string_length || string_key[0]) {
706 141 : return SUCCESS;
707 : }
708 : } else {
709 300 : return SUCCESS;
710 : }
711 36 : if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
712 0 : return FAILURE;
713 : }
714 36 : zend_hash_move_forward_ex(aht, &intern->pos);
715 36 : } while (1);
716 : }
717 1089 : return FAILURE;
718 : }
719 : /* }}} */
720 :
721 : static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
722 1024 : {
723 1024 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
724 :
725 1024 : if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
726 2 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
727 2 : return FAILURE;
728 : } else {
729 1022 : zend_hash_move_forward_ex(aht, &intern->pos);
730 1022 : if (Z_TYPE_P(intern->array) == IS_OBJECT) {
731 206 : return spl_array_skip_protected(intern TSRMLS_CC);
732 : } else {
733 816 : return zend_hash_has_more_elements_ex(aht, &intern->pos);
734 : }
735 : }
736 : } /* }}} */
737 :
738 : /* define an overloaded iterator structure */
739 : typedef struct {
740 : zend_user_iterator intern;
741 : spl_array_object *object;
742 : } spl_array_it;
743 :
744 : static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
745 348 : {
746 348 : spl_array_it *iterator = (spl_array_it *)iter;
747 :
748 348 : zend_user_it_invalidate_current(iter TSRMLS_CC);
749 348 : zval_ptr_dtor((zval**)&iterator->intern.it.data);
750 :
751 348 : efree(iterator);
752 348 : }
753 : /* }}} */
754 :
755 : static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
756 1582 : {
757 1582 : spl_array_it *iterator = (spl_array_it *)iter;
758 1582 : spl_array_object *object = iterator->object;
759 1582 : HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
760 :
761 1582 : if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
762 192 : return zend_user_it_valid(iter TSRMLS_CC);
763 : } else {
764 1390 : if (!aht) {
765 2 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and is no longer an array");
766 2 : return FAILURE;
767 : }
768 :
769 1388 : if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
770 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::valid(): Array was modified outside object and internal position is no longer valid");
771 0 : return FAILURE;
772 : } else {
773 1388 : return zend_hash_has_more_elements_ex(aht, &object->pos);
774 : }
775 : }
776 : }
777 : /* }}} */
778 :
779 : static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
780 786 : {
781 786 : spl_array_it *iterator = (spl_array_it *)iter;
782 786 : spl_array_object *object = iterator->object;
783 786 : HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
784 :
785 786 : if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
786 93 : zend_user_it_get_current_data(iter, data TSRMLS_CC);
787 : } else {
788 693 : if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
789 0 : *data = NULL;
790 : }
791 : }
792 786 : }
793 : /* }}} */
794 :
795 : static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
796 606 : {
797 606 : spl_array_it *iterator = (spl_array_it *)iter;
798 606 : spl_array_object *object = iterator->object;
799 606 : HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
800 :
801 606 : if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
802 72 : return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
803 : } else {
804 534 : if (!aht) {
805 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
806 0 : return HASH_KEY_NON_EXISTANT;
807 : }
808 :
809 534 : if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
810 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and internal position is no longer valid");
811 0 : return HASH_KEY_NON_EXISTANT;
812 : }
813 :
814 534 : return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
815 : }
816 : }
817 : /* }}} */
818 :
819 : static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
820 861 : {
821 861 : spl_array_it *iterator = (spl_array_it *)iter;
822 861 : spl_array_object *object = iterator->object;
823 861 : HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
824 :
825 861 : if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
826 101 : zend_user_it_move_forward(iter TSRMLS_CC);
827 : } else {
828 760 : zend_user_it_invalidate_current(iter TSRMLS_CC);
829 760 : if (!aht) {
830 2 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
831 2 : return;
832 : }
833 :
834 762 : if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(object TSRMLS_CC) == FAILURE) {
835 4 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
836 : } else {
837 754 : spl_array_next(object TSRMLS_CC);
838 : }
839 : }
840 : }
841 : /* }}} */
842 :
843 : static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
844 1324 : {
845 1324 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
846 :
847 1324 : if (!aht) {
848 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
849 0 : return;
850 : }
851 :
852 1324 : zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
853 1324 : spl_array_skip_protected(intern TSRMLS_CC);
854 : }
855 : /* }}} */
856 :
857 : static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
858 346 : {
859 346 : spl_array_it *iterator = (spl_array_it *)iter;
860 346 : spl_array_object *object = iterator->object;
861 :
862 346 : if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
863 65 : zend_user_it_rewind(iter TSRMLS_CC);
864 : } else {
865 281 : zend_user_it_invalidate_current(iter TSRMLS_CC);
866 281 : spl_array_rewind(object TSRMLS_CC);
867 : }
868 346 : }
869 : /* }}} */
870 :
871 : /* iterator handler table */
872 : zend_object_iterator_funcs spl_array_it_funcs = {
873 : spl_array_it_dtor,
874 : spl_array_it_valid,
875 : spl_array_it_get_current_data,
876 : spl_array_it_get_current_key,
877 : spl_array_it_move_forward,
878 : spl_array_it_rewind
879 : };
880 :
881 : zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
882 349 : {
883 : spl_array_it *iterator;
884 349 : spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
885 :
886 349 : if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
887 1 : zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
888 : }
889 :
890 348 : iterator = emalloc(sizeof(spl_array_it));
891 :
892 348 : object->refcount++;
893 348 : iterator->intern.it.data = (void*)object;
894 348 : iterator->intern.it.funcs = &spl_array_it_funcs;
895 348 : iterator->intern.ce = ce;
896 348 : iterator->intern.value = NULL;
897 348 : iterator->object = array_object;
898 :
899 348 : return (zend_object_iterator*)iterator;
900 : }
901 : /* }}} */
902 :
903 : /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
904 : proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
905 : Cronstructs a new array iterator from a path. */
906 : SPL_METHOD(Array, __construct)
907 415 : {
908 415 : zval *object = getThis();
909 : spl_array_object *intern;
910 : zval **array;
911 415 : long ar_flags = 0;
912 415 : zend_class_entry * ce_get_iterator = spl_ce_Iterator;
913 :
914 415 : if (ZEND_NUM_ARGS() == 0) {
915 30 : return; /* nothing to do */
916 : }
917 385 : php_set_error_handling(EH_THROW, spl_ce_InvalidArgumentException TSRMLS_CC);
918 :
919 385 : intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
920 :
921 385 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
922 5 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
923 5 : return;
924 : }
925 :
926 380 : if (Z_TYPE_PP(array) == IS_ARRAY) {
927 325 : SEPARATE_ZVAL_IF_NOT_REF(array);
928 : }
929 :
930 380 : if (ZEND_NUM_ARGS() > 2) {
931 3 : intern->ce_get_iterator = ce_get_iterator;
932 : }
933 :
934 380 : ar_flags &= ~SPL_ARRAY_INT_MASK;
935 :
936 403 : if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
937 23 : zval_ptr_dtor(&intern->array);
938 23 : if (ZEND_NUM_ARGS() == 1)
939 : {
940 10 : spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
941 10 : ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
942 : }
943 23 : ar_flags |= SPL_ARRAY_USE_OTHER;
944 23 : intern->array = *array;
945 : } else {
946 357 : if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
947 1 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
948 1 : zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
949 1 : return;
950 : }
951 356 : zval_ptr_dtor(&intern->array);
952 356 : intern->array = *array;
953 : }
954 379 : if (object == *array) {
955 3 : intern->ar_flags |= SPL_ARRAY_IS_SELF;
956 3 : intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
957 : } else {
958 376 : intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
959 : }
960 379 : intern->ar_flags |= ar_flags;
961 379 : ZVAL_ADDREF(intern->array);
962 379 : if (Z_TYPE_PP(array) == IS_OBJECT) {
963 54 : zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
964 54 : if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
965 : || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
966 0 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
967 0 : 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);
968 0 : return;
969 : }
970 : }
971 :
972 379 : spl_array_rewind(intern TSRMLS_CC);
973 :
974 379 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
975 : }
976 : /* }}} */
977 :
978 : /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
979 : Set the class used in getIterator. */
980 : SPL_METHOD(Array, setIteratorClass)
981 4 : {
982 4 : zval *object = getThis();
983 4 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
984 4 : zend_class_entry * ce_get_iterator = spl_ce_Iterator;
985 :
986 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
987 2 : php_set_error_handling(EH_NORMAL, NULL TSRMLS_CC);
988 2 : return;
989 : }
990 :
991 2 : intern->ce_get_iterator = ce_get_iterator;
992 : }
993 : /* }}} */
994 :
995 : /* {{{ proto string ArrayObject::getIteratorClass()
996 : Get the class used in getIterator. */
997 : SPL_METHOD(Array, getIteratorClass)
998 4 : {
999 4 : zval *object = getThis();
1000 4 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1001 :
1002 4 : RETURN_STRING(intern->ce_get_iterator->name, 1);
1003 : }
1004 : /* }}} */
1005 :
1006 : /* {{{ proto int ArrayObject::getFlags()
1007 : Get flags */
1008 : SPL_METHOD(Array, getFlags)
1009 30 : {
1010 30 : zval *object = getThis();
1011 30 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1012 :
1013 30 : RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
1014 : }
1015 : /* }}} */
1016 :
1017 : /* {{{ proto void ArrayObject::setFlags(int flags)
1018 : Set flags */
1019 : SPL_METHOD(Array, setFlags)
1020 16 : {
1021 16 : zval *object = getThis();
1022 16 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1023 16 : long ar_flags = 0;
1024 :
1025 16 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
1026 0 : return;
1027 : }
1028 :
1029 16 : intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
1030 : }
1031 : /* }}} */
1032 :
1033 : /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
1034 : Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
1035 : SPL_METHOD(Array, exchangeArray)
1036 5 : {
1037 5 : zval *object = getThis(), *tmp, **array;
1038 5 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1039 :
1040 5 : array_init(return_value);
1041 5 : 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*));
1042 :
1043 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
1044 1 : return;
1045 : }
1046 6 : if (Z_TYPE_PP(array) == IS_OBJECT && intern == (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC)) {
1047 2 : zval_ptr_dtor(&intern->array);
1048 2 : array = &object;
1049 2 : intern->array = object;
1050 2 : } else if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
1051 0 : spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
1052 0 : zval_ptr_dtor(&intern->array);
1053 0 : intern->array = other->array;
1054 : } else {
1055 2 : if (Z_TYPE_PP(array) != IS_OBJECT && !HASH_OF(*array)) {
1056 1 : zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
1057 1 : return;
1058 : }
1059 1 : zval_ptr_dtor(&intern->array);
1060 1 : intern->array = *array;
1061 1 : intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
1062 : }
1063 3 : if (object == *array) {
1064 2 : intern->ar_flags |= SPL_ARRAY_IS_SELF;
1065 : } else {
1066 1 : intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
1067 : }
1068 3 : ZVAL_ADDREF(intern->array);
1069 :
1070 3 : spl_array_rewind(intern TSRMLS_CC);
1071 : }
1072 : /* }}} */
1073 :
1074 : /* {{{ proto ArrayIterator ArrayObject::getIterator()
1075 : Create a new iterator from a ArrayObject instance */
1076 : SPL_METHOD(Array, getIterator)
1077 65 : {
1078 65 : zval *object = getThis();
1079 65 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1080 : spl_array_object *iterator;
1081 65 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1082 :
1083 65 : if (!aht) {
1084 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1085 0 : return;
1086 : }
1087 :
1088 65 : return_value->type = IS_OBJECT;
1089 65 : return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
1090 65 : return_value->refcount = 1;
1091 65 : return_value->is_ref = 1;
1092 : }
1093 : /* }}} */
1094 :
1095 : /* {{{ proto void ArrayIterator::rewind()
1096 : Rewind array back to the start */
1097 : SPL_METHOD(Array, rewind)
1098 95 : {
1099 95 : zval *object = getThis();
1100 95 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1101 :
1102 95 : spl_array_rewind(intern TSRMLS_CC);
1103 95 : }
1104 : /* }}} */
1105 :
1106 : /* {{{ proto void ArrayIterator::seek(int $position)
1107 : Seek to position. */
1108 : SPL_METHOD(Array, seek)
1109 27 : {
1110 : long opos, position;
1111 27 : zval *object = getThis();
1112 27 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1113 27 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1114 : int result;
1115 :
1116 27 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
1117 0 : return;
1118 : }
1119 :
1120 27 : if (!aht) {
1121 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1122 0 : return;
1123 : }
1124 :
1125 27 : opos = position;
1126 :
1127 27 : if (position >= 0) { /* negative values are not supported */
1128 26 : spl_array_rewind(intern TSRMLS_CC);
1129 26 : result = SUCCESS;
1130 :
1131 112 : while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
1132 :
1133 26 : if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
1134 25 : return; /* ok */
1135 : }
1136 : }
1137 2 : zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
1138 : } /* }}} */
1139 :
1140 : int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1141 22 : {
1142 22 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1143 22 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1144 : HashPosition pos;
1145 :
1146 22 : if (!aht) {
1147 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1148 0 : *count = 0;
1149 0 : return FAILURE;
1150 : }
1151 :
1152 22 : if (Z_TYPE_P(intern->array) == IS_OBJECT) {
1153 : /* We need to store the 'pos' since we'll modify it in the functions
1154 : * we're going to call and which do not support 'pos' as parameter. */
1155 5 : pos = intern->pos;
1156 5 : *count = 0;
1157 5 : spl_array_rewind(intern TSRMLS_CC);
1158 25 : while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
1159 15 : (*count)++;
1160 : }
1161 5 : intern->pos = pos;
1162 5 : return SUCCESS;
1163 : } else {
1164 17 : *count = zend_hash_num_elements(aht);
1165 17 : return SUCCESS;
1166 : }
1167 : } /* }}} */
1168 :
1169 : /* {{{ proto int ArrayObject::count()
1170 : proto int ArrayIterator::count()
1171 : Return the number of elements in the Iterator. */
1172 : SPL_METHOD(Array, count)
1173 22 : {
1174 : long count;
1175 :
1176 22 : spl_array_object_count_elements(getThis(), &count TSRMLS_CC);
1177 22 : RETURN_LONG(count);
1178 : } /* }}} */
1179 :
1180 : static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg)
1181 17 : {
1182 17 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1183 17 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1184 : zval tmp, *arg;
1185 17 : zval *retval_ptr = NULL;
1186 :
1187 17 : INIT_PZVAL(&tmp);
1188 17 : Z_TYPE(tmp) = IS_ARRAY;
1189 17 : Z_ARRVAL(tmp) = aht;
1190 :
1191 17 : if (use_arg) {
1192 6 : if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1193 4 : zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
1194 4 : return;
1195 : }
1196 2 : zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, &tmp, arg TSRMLS_CC);
1197 : } else {
1198 11 : zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, &tmp, NULL TSRMLS_CC);
1199 : }
1200 13 : if (retval_ptr) {
1201 13 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1202 : }
1203 : }
1204 :
1205 : #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
1206 : SPL_METHOD(cname, fname) \
1207 : { \
1208 : spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
1209 : }
1210 :
1211 : /* {{{ proto int ArrayObject::asort()
1212 : proto int ArrayIterator::asort()
1213 : Sort the entries by values. */
1214 4 : SPL_ARRAY_METHOD(Array, asort, 0)
1215 :
1216 : /* {{{ proto int ArrayObject::ksort()
1217 : proto int ArrayIterator::ksort()
1218 : Sort the entries by key. */
1219 3 : SPL_ARRAY_METHOD(Array, ksort, 0)
1220 :
1221 : /* {{{ proto int ArrayObject::uasort(callback cmp_function)
1222 : proto int ArrayIterator::uasort(callback cmp_function)
1223 : Sort the entries by values user defined function. */
1224 3 : SPL_ARRAY_METHOD(Array, uasort, 1)
1225 :
1226 : /* {{{ proto int ArrayObject::uksort(callback cmp_function)
1227 : proto int ArrayIterator::uksort(callback cmp_function)
1228 : Sort the entries by key using user defined function. */
1229 3 : SPL_ARRAY_METHOD(Array, uksort, 1)
1230 :
1231 : /* {{{ proto int ArrayObject::natsort()
1232 : proto int ArrayIterator::natsort()
1233 : Sort the entries by values using "natural order" algorithm. */
1234 2 : SPL_ARRAY_METHOD(Array, natsort, 0)
1235 :
1236 : /* {{{ proto int ArrayObject::natcasesort()
1237 : proto int ArrayIterator::natcasesort()
1238 : Sort the entries by key using case insensitive "natural order" algorithm. */
1239 2 : SPL_ARRAY_METHOD(Array, natcasesort, 0)
1240 :
1241 : /* {{{ proto mixed|NULL ArrayIterator::current()
1242 : Return current array entry */
1243 : SPL_METHOD(Array, current)
1244 188 : {
1245 188 : zval *object = getThis();
1246 188 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1247 : zval **entry;
1248 188 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1249 :
1250 188 : if (!aht) {
1251 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1252 0 : return;
1253 : }
1254 :
1255 188 : if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
1256 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1257 0 : return;
1258 : }
1259 :
1260 188 : if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1261 0 : return;
1262 : }
1263 188 : RETVAL_ZVAL(*entry, 1, 0);
1264 : }
1265 : /* }}} */
1266 :
1267 : /* {{{ proto mixed|NULL ArrayIterator::key()
1268 : Return current array key */
1269 : SPL_METHOD(Array, key)
1270 141 : {
1271 141 : spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
1272 141 : }
1273 :
1274 : void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
1275 147 : {
1276 147 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1277 : char *string_key;
1278 : uint string_length;
1279 : ulong num_key;
1280 147 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1281 :
1282 147 : if (!aht) {
1283 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1284 0 : return;
1285 : }
1286 :
1287 147 : if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
1288 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1289 0 : return;
1290 : }
1291 :
1292 147 : switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
1293 : case HASH_KEY_IS_STRING:
1294 13 : RETVAL_STRINGL(string_key, string_length - 1, 0);
1295 13 : break;
1296 : case HASH_KEY_IS_LONG:
1297 134 : RETVAL_LONG(num_key);
1298 134 : break;
1299 : case HASH_KEY_NON_EXISTANT:
1300 0 : return;
1301 : }
1302 : }
1303 : /* }}} */
1304 :
1305 : /* {{{ proto void ArrayIterator::next()
1306 : Move to next entry */
1307 : SPL_METHOD(Array, next)
1308 168 : {
1309 168 : zval *object = getThis();
1310 168 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1311 168 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1312 :
1313 168 : if (!aht) {
1314 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1315 0 : return;
1316 : }
1317 :
1318 168 : spl_array_next(intern TSRMLS_CC);
1319 : }
1320 : /* }}} */
1321 :
1322 : /* {{{ proto bool ArrayIterator::valid()
1323 : Check whether array contains more entries */
1324 : SPL_METHOD(Array, valid)
1325 430 : {
1326 430 : zval *object = getThis();
1327 430 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1328 430 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1329 :
1330 430 : if (!aht) {
1331 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1332 0 : return;
1333 : }
1334 :
1335 430 : if (intern->pos && (intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
1336 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1337 0 : RETURN_FALSE;
1338 : } else {
1339 430 : RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
1340 : }
1341 : }
1342 : /* }}} */
1343 :
1344 : /* {{{ proto bool RecursiveArrayIterator::hasChildren()
1345 : Check whether current element has children (e.g. is an array) */
1346 : SPL_METHOD(Array, hasChildren)
1347 491 : {
1348 491 : zval *object = getThis(), **entry;
1349 491 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1350 491 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1351 :
1352 491 : if (!aht) {
1353 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1354 0 : RETURN_FALSE;
1355 : }
1356 :
1357 491 : if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
1358 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1359 0 : RETURN_FALSE;
1360 : }
1361 :
1362 491 : if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1363 9 : RETURN_FALSE;
1364 : }
1365 :
1366 482 : RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT);
1367 : }
1368 : /* }}} */
1369 :
1370 : /* {{{ proto object RecursiveArrayIterator::getChildren()
1371 : Create a sub iterator for the current element (same class as $this) */
1372 : SPL_METHOD(Array, getChildren)
1373 108 : {
1374 108 : zval *object = getThis(), **entry, *flags;
1375 108 : spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1376 108 : HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1377 :
1378 108 : if (!aht) {
1379 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1380 0 : return;
1381 : }
1382 :
1383 108 : if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos(intern TSRMLS_CC) == FAILURE) {
1384 0 : php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
1385 0 : return;
1386 : }
1387 :
1388 108 : if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1389 0 : return;
1390 : }
1391 :
1392 108 : if (Z_TYPE_PP(entry) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
1393 0 : RETURN_ZVAL(*entry, 0, 0);
1394 : }
1395 :
1396 108 : MAKE_STD_ZVAL(flags);
1397 108 : ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER);
1398 108 : spl_instantiate_arg_ex2(intern->std.ce, &return_value, 0, *entry, flags TSRMLS_CC);
1399 108 : zval_ptr_dtor(&flags);
1400 : }
1401 : /* }}} */
1402 :
1403 : static
1404 : ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
1405 : ZEND_ARG_INFO(0, array)
1406 : ZEND_END_ARG_INFO()
1407 :
1408 : static
1409 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
1410 : ZEND_ARG_INFO(0, index)
1411 : ZEND_END_ARG_INFO()
1412 :
1413 : static
1414 : ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
1415 : ZEND_ARG_INFO(0, index)
1416 : ZEND_ARG_INFO(0, newval)
1417 : ZEND_END_ARG_INFO()
1418 :
1419 : static
1420 : ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
1421 : ZEND_ARG_INFO(0, value)
1422 : ZEND_END_ARG_INFO()
1423 :
1424 : static
1425 : ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
1426 : ZEND_ARG_INFO(0, position)
1427 : ZEND_END_ARG_INFO()
1428 :
1429 : static
1430 : ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
1431 : ZEND_ARG_INFO(0, array)
1432 : ZEND_END_ARG_INFO()
1433 :
1434 : static
1435 : ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
1436 : ZEND_ARG_INFO(0, flags)
1437 : ZEND_END_ARG_INFO()
1438 :
1439 : static
1440 : ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
1441 : ZEND_ARG_INFO(0, iteratorClass)
1442 : ZEND_END_ARG_INFO()
1443 :
1444 : static
1445 : ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
1446 : ZEND_ARG_INFO(0, cmp_function )
1447 : ZEND_END_ARG_INFO();
1448 :
1449 : static zend_function_entry spl_funcs_ArrayObject[] = {
1450 : SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1451 : SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1452 : SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1453 : SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1454 : SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1455 : SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1456 : SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
1457 : SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
1458 : SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
1459 : SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1460 : SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
1461 : SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
1462 : SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1463 : SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1464 : SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
1465 : SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
1466 : /* ArrayObject specific */
1467 : SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC)
1468 : SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
1469 : SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
1470 : SPL_ME(Array, getIteratorClass, NULL, ZEND_ACC_PUBLIC)
1471 : {NULL, NULL, NULL}
1472 : };
1473 :
1474 : static zend_function_entry spl_funcs_ArrayIterator[] = {
1475 : SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1476 : SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1477 : SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1478 : SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1479 : SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1480 : SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1481 : SPL_ME(Array, getArrayCopy, NULL, ZEND_ACC_PUBLIC)
1482 : SPL_ME(Array, count, NULL, ZEND_ACC_PUBLIC)
1483 : SPL_ME(Array, getFlags, NULL, ZEND_ACC_PUBLIC)
1484 : SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1485 : SPL_ME(Array, asort, NULL, ZEND_ACC_PUBLIC)
1486 : SPL_ME(Array, ksort, NULL, ZEND_ACC_PUBLIC)
1487 : SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1488 : SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1489 : SPL_ME(Array, natsort, NULL, ZEND_ACC_PUBLIC)
1490 : SPL_ME(Array, natcasesort, NULL, ZEND_ACC_PUBLIC)
1491 : /* ArrayIterator specific */
1492 : SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC)
1493 : SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC)
1494 : SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC)
1495 : SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC)
1496 : SPL_ME(Array, valid, NULL, ZEND_ACC_PUBLIC)
1497 : SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
1498 : {NULL, NULL, NULL}
1499 : };
1500 :
1501 : static zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
1502 : SPL_ME(Array, hasChildren, NULL, ZEND_ACC_PUBLIC)
1503 : SPL_ME(Array, getChildren, NULL, ZEND_ACC_PUBLIC)
1504 : {NULL, NULL, NULL}
1505 : };
1506 :
1507 : /* {{{ PHP_MINIT_FUNCTION(spl_array) */
1508 : PHP_MINIT_FUNCTION(spl_array)
1509 13565 : {
1510 13565 : REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
1511 13565 : REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
1512 13565 : REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
1513 13565 : memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1514 :
1515 13565 : spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
1516 13565 : spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
1517 13565 : spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
1518 13565 : spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
1519 13565 : spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
1520 13565 : spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
1521 :
1522 13565 : spl_handler_ArrayObject.get_properties = spl_array_get_properties;
1523 13565 : spl_handler_ArrayObject.read_property = spl_array_read_property;
1524 13565 : spl_handler_ArrayObject.write_property = spl_array_write_property;
1525 13565 : spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
1526 13565 : spl_handler_ArrayObject.has_property = spl_array_has_property;
1527 13565 : spl_handler_ArrayObject.unset_property = spl_array_unset_property;
1528 :
1529 13565 : REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
1530 13565 : REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
1531 13565 : REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
1532 13565 : REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
1533 13565 : memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
1534 13565 : spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
1535 :
1536 13565 : REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
1537 13565 : REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
1538 13565 : spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
1539 :
1540 13565 : REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
1541 13565 : REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
1542 :
1543 13565 : REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1544 13565 : REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1545 :
1546 13565 : REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1547 13565 : REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1548 13565 : return SUCCESS;
1549 : }
1550 : /* }}} */
1551 :
1552 : /*
1553 : * Local variables:
1554 : * tab-width: 4
1555 : * c-basic-offset: 4
1556 : * End:
1557 : * vim600: fdm=marker
1558 : * vim: noet sw=4 ts=4
1559 : */
|