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