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