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