php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
spl_array.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Marcus Boerger <helly@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18# include "config.h"
19#endif
20
21#include "php.h"
23#include "zend_smart_str.h"
24#include "zend_interfaces.h"
25#include "zend_exceptions.h"
26
27#include "spl_iterators.h"
28#include "spl_array.h"
29#include "spl_array_arginfo.h"
30#include "spl_exceptions.h"
31#include "spl_functions.h" /* For spl_set_private_debug_info_property() */
32
33/* Defined later in the file */
36
37/* ArrayObject class */
38static zend_object_handlers spl_handler_ArrayObject;
40
57
58static inline spl_array_object *spl_array_from_obj(zend_object *obj) /* {{{ */ {
59 return (spl_array_object*)((char*)(obj) - XtOffsetOf(spl_array_object, std));
60}
61/* }}} */
62
63#define Z_SPLARRAY_P(zv) spl_array_from_obj(Z_OBJ_P((zv)))
64
65static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern) { /* {{{ */
66 //??? TODO: Delay duplication for arrays; only duplicate for write operations
67 if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
68 /* rebuild properties */
69 zend_std_get_properties_ex(&intern->std);
70 return &intern->std.properties;
71 } else if (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
72 spl_array_object *other = Z_SPLARRAY_P(&intern->array);
73 return spl_array_get_hash_table_ptr(other);
74 } else if (Z_TYPE(intern->array) == IS_ARRAY) {
75 return &Z_ARRVAL(intern->array);
76 } else {
77 zend_object *obj = Z_OBJ(intern->array);
78 /* Since we're directly playing with the properties table, we shall initialize the lazy object directly.
79 * If we don't, it's possible to continue working with the wrong object in case we're using a proxy. */
80 if (UNEXPECTED(zend_lazy_object_must_init(obj))) {
81 obj = zend_lazy_object_init(obj);
82 if (UNEXPECTED(!obj)) {
83 if (!intern->sentinel_array) {
84 intern->sentinel_array = zend_new_array(0);
85 }
86 return &intern->sentinel_array;
87 }
88 }
89 /* should no longer be lazy */
90 ZEND_ASSERT(!zend_lazy_object_must_init(obj));
91 /* rebuild properties */
92 zend_std_get_properties_ex(obj);
93 if (GC_REFCOUNT(obj->properties) > 1) {
96 }
98 }
99 return &obj->properties;
100 }
101}
102/* }}} */
103
104static inline HashTable *spl_array_get_hash_table(spl_array_object* intern) { /* {{{ */
105 return *spl_array_get_hash_table_ptr(intern);
106}
107/* }}} */
108
109static inline bool spl_array_is_object(spl_array_object *intern) /* {{{ */
110{
111 while (intern->ar_flags & SPL_ARRAY_USE_OTHER) {
112 intern = Z_SPLARRAY_P(&intern->array);
113 }
114 return (intern->ar_flags & SPL_ARRAY_IS_SELF) || Z_TYPE(intern->array) == IS_OBJECT;
115}
116/* }}} */
117
118static zend_result spl_array_skip_protected(spl_array_object *intern, HashTable *aht);
119
120static zend_never_inline void spl_array_create_ht_iter(HashTable *ht, spl_array_object* intern) /* {{{ */
121{
123 zend_hash_internal_pointer_reset_ex(ht, &EG(ht_iterators)[intern->ht_iter].pos);
124 spl_array_skip_protected(intern, ht);
125}
126/* }}} */
127
128static zend_always_inline uint32_t *spl_array_get_pos_ptr(HashTable *ht, spl_array_object* intern) /* {{{ */
129{
130 if (UNEXPECTED(intern->ht_iter == (uint32_t)-1)) {
131 spl_array_create_ht_iter(ht, intern);
132 }
133 return &EG(ht_iterators)[intern->ht_iter].pos;
134}
135/* }}} */
136
137/* {{{ spl_array_object_free_storage */
138static void spl_array_object_free_storage(zend_object *object)
139{
140 spl_array_object *intern = spl_array_from_obj(object);
141
142 if (intern->ht_iter != (uint32_t) -1) {
144 }
145
146 if (UNEXPECTED(intern->sentinel_array)) {
147 zend_array_release(intern->sentinel_array);
148 }
149
150 zend_object_std_dtor(&intern->std);
151
152 zval_ptr_dtor(&intern->array);
153}
154/* }}} */
155
156/* {{{ spl_array_object_new_ex */
157static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_object *orig, int clone_orig)
158{
159 spl_array_object *intern;
160 zend_class_entry *parent = class_type;
161 int inherited = 0;
162
163 intern = zend_object_alloc(sizeof(spl_array_object), 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->is_child = false;
170 intern->bucket = NULL;
172 if (orig) {
173 spl_array_object *other = spl_array_from_obj(orig);
174
175 intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
176 intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
177 intern->ce_get_iterator = other->ce_get_iterator;
178 if (clone_orig) {
179 if (other->ar_flags & SPL_ARRAY_IS_SELF) {
180 ZVAL_UNDEF(&intern->array);
181 } else if (instanceof_function(class_type, spl_ce_ArrayObject)) {
182 ZVAL_ARR(&intern->array,
183 zend_array_dup(spl_array_get_hash_table(other)));
184 } else {
185 #if ZEND_DEBUG
186 /* This is because the call to instanceof_function will remain because
187 * the compiler can't prove in this compile unit that this function is
188 * side-effect-free.
189 * See https://github.com/php/php-src/pull/14518#discussion_r1638740932 */
190 ZEND_ASSERT(instanceof_function(class_type, spl_ce_ArrayIterator));
191 #endif
192
193 ZVAL_OBJ_COPY(&intern->array, orig);
194 intern->ar_flags |= SPL_ARRAY_USE_OTHER;
195 }
196 } else {
197 ZVAL_OBJ_COPY(&intern->array, orig);
198 intern->ar_flags |= SPL_ARRAY_USE_OTHER;
199 }
200 } else {
201 array_init(&intern->array);
202 }
203
204 while (parent) {
205 if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator || parent == spl_ce_ArrayObject) {
206 break;
207 }
208 parent = parent->parent;
209 inherited = 1;
210 }
211
212 ZEND_ASSERT(parent);
213
214 if (inherited) {
215 intern->fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
216 if (intern->fptr_offset_get->common.scope == parent) {
217 intern->fptr_offset_get = NULL;
218 }
219 intern->fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
220 if (intern->fptr_offset_set->common.scope == parent) {
221 intern->fptr_offset_set = NULL;
222 }
223 intern->fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
224 if (intern->fptr_offset_has->common.scope == parent) {
225 intern->fptr_offset_has = NULL;
226 }
227 intern->fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
228 if (intern->fptr_offset_del->common.scope == parent) {
229 intern->fptr_offset_del = NULL;
230 }
231 /* Find count() method */
232 intern->fptr_count = zend_hash_find_ptr(&class_type->function_table, ZSTR_KNOWN(ZEND_STR_COUNT));
233 if (intern->fptr_count->common.scope == parent) {
234 intern->fptr_count = NULL;
235 }
236 }
237
238 intern->ht_iter = (uint32_t)-1;
239 return &intern->std;
240}
241/* }}} */
242
243/* {{{ spl_array_object_new */
244static zend_object *spl_array_object_new(zend_class_entry *class_type)
245{
246 return spl_array_object_new_ex(class_type, NULL, 0);
247}
248/* }}} */
249
250/* {{{ spl_array_object_clone */
251static zend_object *spl_array_object_clone(zend_object *old_object)
252{
253 zend_object *new_object;
254
255 new_object = spl_array_object_new_ex(old_object->ce, old_object, 1);
256
257 zend_objects_clone_members(new_object, old_object);
258
259 return new_object;
260}
261/* }}} */
262
268
269static void spl_hash_key_release(spl_hash_key *key) {
270 if (key->release_key) {
272 }
273}
274
275/* This function does not throw any exceptions for illegal offsets, calls to
276 * zend_illegal_container_offset(); need to be made if the return value is FAILURE */
277static zend_result get_hash_key(spl_hash_key *key, spl_array_object *intern, zval *offset)
278{
279 key->release_key = false;
280try_again:
281 switch (Z_TYPE_P(offset)) {
282 case IS_NULL:
283 key->key = ZSTR_EMPTY_ALLOC();
284 return SUCCESS;
285 case IS_STRING:
286 key->key = Z_STR_P(offset);
287 if (ZEND_HANDLE_NUMERIC(key->key, key->h)) {
288 key->key = NULL;
289 break;
290 }
291 return SUCCESS;
292 case IS_RESOURCE:
294 key->key = NULL;
295 key->h = Z_RES_P(offset)->handle;
296 break;
297 case IS_DOUBLE:
298 key->key = NULL;
299 key->h = zend_dval_to_lval_safe(Z_DVAL_P(offset));
300 break;
301 case IS_FALSE:
302 key->key = NULL;
303 key->h = 0;
304 break;
305 case IS_TRUE:
306 key->key = NULL;
307 key->h = 1;
308 break;
309 case IS_LONG:
310 key->key = NULL;
311 key->h = Z_LVAL_P(offset);
312 break;
313 case IS_REFERENCE:
315 goto try_again;
316 default:
317 return FAILURE;
318 }
319
320 if (spl_array_is_object(intern)) {
321 key->key = zend_long_to_str(key->h);
322 key->release_key = true;
323 }
324 return SUCCESS;
325}
326
327static zval *spl_array_get_dimension_ptr(bool check_inherited, spl_array_object *intern, const zend_string *ce_name,
328 zval *offset, int type) /* {{{ */
329{
330 zval *retval;
332 HashTable *ht = spl_array_get_hash_table(intern);
333
334 if (!offset || Z_ISUNDEF_P(offset) || !ht) {
335 return &EG(uninitialized_zval);
336 }
337
338 if ((type == BP_VAR_W || type == BP_VAR_RW) && intern->nApplyCount > 0) {
339 zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
340 return &EG(error_zval);
341 }
342
343 if (get_hash_key(&key, intern, offset) == FAILURE) {
345 return (type == BP_VAR_W || type == BP_VAR_RW) ?
346 &EG(error_zval) : &EG(uninitialized_zval);
347 }
348
349 if (key.key) {
350 retval = zend_hash_find(ht, key.key);
351 if (retval) {
352 if (Z_TYPE_P(retval) == IS_INDIRECT) {
354 if (Z_TYPE_P(retval) == IS_UNDEF) {
355 switch (type) {
356 case BP_VAR_R:
357 zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key.key));
359 case BP_VAR_UNSET:
360 case BP_VAR_IS:
361 retval = &EG(uninitialized_zval);
362 break;
363 case BP_VAR_RW:
364 zend_error(E_WARNING,"Undefined array key \"%s\"", ZSTR_VAL(key.key));
366 case BP_VAR_W: {
368 }
369 }
370 }
371 }
372 } else {
373 switch (type) {
374 case BP_VAR_R:
375 zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(key.key));
377 case BP_VAR_UNSET:
378 case BP_VAR_IS:
379 retval = &EG(uninitialized_zval);
380 break;
381 case BP_VAR_RW:
382 zend_error(E_WARNING,"Undefined array key \"%s\"", ZSTR_VAL(key.key));
384 case BP_VAR_W: {
385 zval value;
388 }
389 }
390 }
391 spl_hash_key_release(&key);
392 } else {
393 if ((retval = zend_hash_index_find(ht, key.h)) == NULL) {
394 switch (type) {
395 case BP_VAR_R:
396 zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, key.h);
398 case BP_VAR_UNSET:
399 case BP_VAR_IS:
400 retval = &EG(uninitialized_zval);
401 break;
402 case BP_VAR_RW:
403 zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, key.h);
405 case BP_VAR_W: {
406 zval value;
409 }
410 }
411 }
412 }
413 return retval;
414} /* }}} */
415
416static int spl_array_has_dimension(zend_object *object, zval *offset, int check_empty);
417
418static zval *spl_array_read_dimension_ex(int check_inherited, zend_object *object, zval *offset, int type, zval *rv) /* {{{ */
419{
420 spl_array_object *intern = spl_array_from_obj(object);
421 zval *ret;
422
423 if (check_inherited &&
424 (intern->fptr_offset_get || (type == BP_VAR_IS && intern->fptr_offset_has))) {
425 if (type == BP_VAR_IS) {
426 if (!spl_array_has_dimension(object, offset, 0)) {
427 return &EG(uninitialized_zval);
428 }
429 }
430
431 if (intern->fptr_offset_get) {
432 zval tmp;
433 if (!offset) {
434 ZVAL_UNDEF(&tmp);
435 offset = &tmp;
436 }
437 zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_get, "offsetGet", rv, offset);
438
439 if (!Z_ISUNDEF_P(rv)) {
440 return rv;
441 }
442 return &EG(uninitialized_zval);
443 }
444 }
445
446 ret = spl_array_get_dimension_ptr(check_inherited, intern, object->ce->name, offset, type);
447
448 /* When in a write context,
449 * ZE has to be fooled into thinking this is in a reference set
450 * by separating (if necessary) and returning as IS_REFERENCE (with refcount == 1)
451 */
452
453 if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) &&
454 !Z_ISREF_P(ret) &&
455 EXPECTED(ret != &EG(uninitialized_zval))) {
457 }
458
459 return ret;
460} /* }}} */
461
462static zval *spl_array_read_dimension(zend_object *object, zval *offset, int type, zval *rv) /* {{{ */
463{
464 return spl_array_read_dimension_ex(1, object, offset, type, rv);
465} /* }}} */
466
467/*
468 * The assertion(HT_ASSERT_RC1(ht)) failed because the refcount was increased manually when intern->is_child is true.
469 * We have to set the refcount to 1 to make assertion success and restore the refcount to the original value after
470 * modifying the array when intern->is_child is true.
471 */
472static uint32_t spl_array_set_refcount(bool is_child, HashTable *ht, uint32_t refcount) /* {{{ */
473{
474 uint32_t old_refcount = 0;
475 if (is_child) {
476 old_refcount = GC_REFCOUNT(ht);
477 GC_SET_REFCOUNT(ht, refcount);
478 }
479
480 return old_refcount;
481} /* }}} */
482
483static void spl_array_write_dimension_ex(int check_inherited, zend_object *object, zval *offset, zval *value) /* {{{ */
484{
485 spl_array_object *intern = spl_array_from_obj(object);
486 HashTable *ht;
488
489 if (check_inherited && intern->fptr_offset_set) {
490 zval tmp;
491
492 if (!offset) {
493 ZVAL_NULL(&tmp);
494 offset = &tmp;
495 }
496 zend_call_method_with_2_params(object, object->ce, &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
497 return;
498 }
499
500 if (intern->nApplyCount > 0) {
501 zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
502 return;
503 }
504
506
507 uint32_t refcount = 0;
508 if (!offset || Z_TYPE_P(offset) == IS_NULL) {
509 ht = spl_array_get_hash_table(intern);
510 if (UNEXPECTED(ht == intern->sentinel_array)) {
511 return;
512 }
513 refcount = spl_array_set_refcount(intern->is_child, ht, 1);
515
516 if (refcount) {
517 spl_array_set_refcount(intern->is_child, ht, refcount);
518 }
519 return;
520 }
521
522 if (get_hash_key(&key, intern, offset) == FAILURE) {
525 return;
526 }
527
528 ht = spl_array_get_hash_table(intern);
529 if (UNEXPECTED(ht == intern->sentinel_array)) {
530 spl_hash_key_release(&key);
531 return;
532 }
533 refcount = spl_array_set_refcount(intern->is_child, ht, 1);
534 if (key.key) {
536 spl_hash_key_release(&key);
537 } else {
539 }
540
541 if (refcount) {
542 spl_array_set_refcount(intern->is_child, ht, refcount);
543 }
544} /* }}} */
545
546static void spl_array_write_dimension(zend_object *object, zval *offset, zval *value) /* {{{ */
547{
548 spl_array_write_dimension_ex(1, object, offset, value);
549} /* }}} */
550
551static void spl_array_unset_dimension_ex(int check_inherited, zend_object *object, zval *offset) /* {{{ */
552{
553 HashTable *ht;
554 spl_array_object *intern = spl_array_from_obj(object);
556
557 if (check_inherited && intern->fptr_offset_del) {
558 zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_del, "offsetUnset", NULL, offset);
559 return;
560 }
561
562 if (intern->nApplyCount > 0) {
563 zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
564 return;
565 }
566
567 if (get_hash_key(&key, intern, offset) == FAILURE) {
569 return;
570 }
571
572 ht = spl_array_get_hash_table(intern);
573 uint32_t refcount = spl_array_set_refcount(intern->is_child, ht, 1);
574
575 if (key.key) {
576 zval *data = zend_hash_find(ht, key.key);
577 if (data) {
578 if (Z_TYPE_P(data) == IS_INDIRECT) {
580 if (Z_TYPE_P(data) != IS_UNDEF) {
585 zend_hash_move_forward_ex(ht, spl_array_get_pos_ptr(ht, intern));
586 if (spl_array_is_object(intern)) {
587 spl_array_skip_protected(intern, ht);
588 }
590 }
591 } else {
592 zend_hash_del(ht, key.key);
593 }
594 }
595 spl_hash_key_release(&key);
596 } else {
598 }
599
600 if (refcount) {
601 spl_array_set_refcount(intern->is_child, ht, refcount);
602 }
603} /* }}} */
604
605static void spl_array_unset_dimension(zend_object *object, zval *offset) /* {{{ */
606{
607 spl_array_unset_dimension_ex(1, object, offset);
608} /* }}} */
609
610/* check_empty can take value 0, 1, or 2
611 * 0/1 are used as normal boolean, but 2 is used for the case when this function is called from
612 * the offsetExists() method, in which case it needs to report the offset exist even if the value is null */
613static bool spl_array_has_dimension_ex(bool check_inherited, zend_object *object, zval *offset, int check_empty) /* {{{ */
614{
615 spl_array_object *intern = spl_array_from_obj(object);
616 zval rv, *value = NULL, *tmp;
617
618 if (check_inherited && intern->fptr_offset_has) {
619 zend_call_method_with_1_params(object, object->ce, &intern->fptr_offset_has, "offsetExists", &rv, offset);
620
621 if (!zend_is_true(&rv)) {
623 return 0;
624 }
626
627 /* For isset calls we don't need to check the value, so return early */
628 if (!check_empty) {
629 return 1;
630 } else if (intern->fptr_offset_get) {
631 value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R, &rv);
632 }
633 }
634
635 if (!value) {
636 HashTable *ht = spl_array_get_hash_table(intern);
638
639 if (get_hash_key(&key, intern, offset) == FAILURE) {
641 return 0;
642 }
643
644 if (key.key) {
645 tmp = zend_hash_find(ht, key.key);
646 spl_hash_key_release(&key);
647 } else {
648 tmp = zend_hash_index_find(ht, key.h);
649 }
650
651 if (!tmp) {
652 return 0;
653 }
654
655 /* check_empty is only equal to 2 if it is called from offsetExists on this class,
656 * where it needs to report an offset exists even if the value is null */
657 if (check_empty == 2) {
658 return 1;
659 }
660
661 if (check_empty && check_inherited && intern->fptr_offset_get) {
662 value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R, &rv);
663 } else {
664 value = tmp;
665 }
666 }
667
668 /* empty() check the value is not falsy, isset() only check it is not null */
669 bool result = check_empty ? zend_is_true(value) : Z_TYPE_P(value) != IS_NULL;
670
671 if (value == &rv) {
673 }
674
675 return result;
676} /* }}} */
677
678static int spl_array_has_dimension(zend_object *object, zval *offset, int check_empty) /* {{{ */
679{
680 return spl_array_has_dimension_ex(/* check_inherited */ true, object, offset, check_empty);
681} /* }}} */
682
683/* {{{ Returns whether the requested $index exists. */
685{
686 zval *index;
687 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
689 }
690 RETURN_BOOL(spl_array_has_dimension_ex(/* check_inherited */ false, Z_OBJ_P(ZEND_THIS), index, 2));
691} /* }}} */
692
693/* {{{ Returns the value at the specified $index. */
695{
696 zval *value, *index;
697 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
699 }
700 value = spl_array_read_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, BP_VAR_R, return_value);
701 if (value != return_value) {
703 }
704} /* }}} */
705
706/* {{{ Sets the value at the specified $index to $newval. */
708{
709 zval *index, *value;
710 if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &index, &value) == FAILURE) {
712 }
713 spl_array_write_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index, value);
714} /* }}} */
715
716void spl_array_iterator_append(zval *object, zval *append_value) /* {{{ */
717{
718 spl_array_object *intern = Z_SPLARRAY_P(object);
719
720 if (spl_array_is_object(intern)) {
721 zend_throw_error(NULL, "Cannot append properties to objects, use %s::offsetSet() instead", ZSTR_VAL(Z_OBJCE_P(object)->name));
722 return;
723 }
724
725 spl_array_write_dimension(Z_OBJ_P(object), NULL, append_value);
726} /* }}} */
727
728/* {{{ Appends the value (cannot be called for objects). */
730{
731 zval *value;
732
735 }
737} /* }}} */
738
739/* {{{ Unsets the value at the specified $index. */
741{
742 zval *index;
743 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &index) == FAILURE) {
745 }
746 spl_array_unset_dimension_ex(0, Z_OBJ_P(ZEND_THIS), index);
747} /* }}} */
748
749/* {{{ Return a copy of the contained array */
751{
752 zval *object = ZEND_THIS;
753 spl_array_object *intern = Z_SPLARRAY_P(object);
754
757 }
758
759 RETURN_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
760} /* }}} */
761
762static HashTable *spl_array_get_properties_for(zend_object *object, zend_prop_purpose purpose) /* {{{ */
763{
764 spl_array_object *intern = spl_array_from_obj(object);
765 HashTable *ht;
766 bool dup;
767
768 if (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) {
769 return zend_std_get_properties_for(object, purpose);
770 }
771
772 /* We are supposed to be the only owner of the internal hashtable.
773 * The "dup" flag decides whether this is a "long-term" use where
774 * we need to duplicate, or a "temporary" one, where we can expect
775 * that no operations on the ArrayObject will be performed in the
776 * meantime. */
777 switch (purpose) {
779 dup = 1;
780 break;
783 dup = 0;
784 break;
785 default:
786 return zend_std_get_properties_for(object, purpose);
787 }
788
789 ht = spl_array_get_hash_table(intern);
790 if (dup) {
792 } else {
793 GC_ADDREF(ht);
794 }
795 return ht;
796} /* }}} */
797
798static inline HashTable* spl_array_get_debug_info(zend_object *obj) /* {{{ */
799{
800 spl_array_object *intern = spl_array_from_obj(obj);
801 HashTable *properties = zend_std_get_properties_ex(&intern->std);
802
803 if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
804 return zend_array_dup(properties);
805 } else {
806 HashTable *debug_info;
807
808 debug_info = zend_new_array(zend_hash_num_elements(properties) + 1);
809 zend_hash_copy(debug_info, properties, (copy_ctor_func_t) zval_add_ref);
810
811 zval *storage = &intern->array;
812 Z_TRY_ADDREF_P(storage);
813
814 const zend_class_entry *base_class_ce = instanceof_function(obj->ce, spl_ce_ArrayIterator)
816
817 spl_set_private_debug_info_property(base_class_ce, "storage", strlen("storage"), debug_info, storage);
818
819 return debug_info;
820 }
821}
822/* }}} */
823
824static HashTable *spl_array_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
825{
826 spl_array_object *intern = spl_array_from_obj(obj);
827 *gc_data = &intern->array;
828 *gc_data_count = 1;
829 return zend_std_get_properties(obj);
830}
831/* }}} */
832
833static zval *spl_array_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv) /* {{{ */
834{
835 spl_array_object *intern = spl_array_from_obj(object);
836
837 if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
839 zval member;
840 ZVAL_STR(&member, name);
841 return spl_array_read_dimension(object, &member, type, rv);
842 }
843 return zend_std_read_property(object, name, type, cache_slot, rv);
844} /* }}} */
845
846static zval *spl_array_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot) /* {{{ */
847{
848 spl_array_object *intern = spl_array_from_obj(object);
849
850 if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
852 zval member;
853 ZVAL_STR(&member, name);
854 spl_array_write_dimension(object, &member, value);
855 return value;
856 }
857 return zend_std_write_property(object, name, value, cache_slot);
858} /* }}} */
859
860static zval *spl_array_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) /* {{{ */
861{
862 spl_array_object *intern = spl_array_from_obj(object);
863
864 if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
866 if (cache_slot) {
867 cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL;
868 }
869
870 /* If object has offsetGet() overridden, then fallback to read_property,
871 * which will call offsetGet(). */
872 zval member;
873 if (intern->fptr_offset_get) {
874 return NULL;
875 }
876 ZVAL_STR(&member, name);
877 return spl_array_get_dimension_ptr(1, intern, object->ce->name, &member, type);
878 }
879 return zend_std_get_property_ptr_ptr(object, name, type, cache_slot);
880} /* }}} */
881
882static int spl_array_has_property(zend_object *object, zend_string *name, int has_set_exists, void **cache_slot) /* {{{ */
883{
884 spl_array_object *intern = spl_array_from_obj(object);
885
886 if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
888 zval member;
889 ZVAL_STR(&member, name);
890 return spl_array_has_dimension(object, &member, has_set_exists);
891 }
892 return zend_std_has_property(object, name, has_set_exists, cache_slot);
893} /* }}} */
894
895static void spl_array_unset_property(zend_object *object, zend_string *name, void **cache_slot) /* {{{ */
896{
897 spl_array_object *intern = spl_array_from_obj(object);
898
899 if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
901 zval member;
902 ZVAL_STR(&member, name);
903 spl_array_unset_dimension(object, &member);
904 return;
905 }
906 zend_std_unset_property(object, name, cache_slot);
907} /* }}} */
908
909static int spl_array_compare_objects(zval *o1, zval *o2) /* {{{ */
910{
911 HashTable *ht1,
912 *ht2;
913 spl_array_object *intern1,
914 *intern2;
915 int result = 0;
916
918
919 intern1 = Z_SPLARRAY_P(o1);
920 intern2 = Z_SPLARRAY_P(o2);
921 ht1 = spl_array_get_hash_table(intern1);
922 ht2 = spl_array_get_hash_table(intern2);
923
925 /* if we just compared std.properties, don't do it again */
926 if (result == 0 &&
927 !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
929 }
930 return result;
931} /* }}} */
932
933static zend_result spl_array_skip_protected(spl_array_object *intern, HashTable *aht) /* {{{ */
934{
935 zend_string *string_key;
936 zend_ulong num_key;
937 zval *data;
938
939 if (spl_array_is_object(intern)) {
940 uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
941
942 do {
943 if (zend_hash_get_current_key_ex(aht, &string_key, &num_key, pos_ptr) == HASH_KEY_IS_STRING) {
944 data = zend_hash_get_current_data_ex(aht, pos_ptr);
945 if (data && Z_TYPE_P(data) == IS_INDIRECT &&
947 /* skip */
948 } else if (!ZSTR_LEN(string_key) || ZSTR_VAL(string_key)[0]) {
949 return SUCCESS;
950 }
951 } else {
952 return SUCCESS;
953 }
954 if (zend_hash_has_more_elements_ex(aht, pos_ptr) != SUCCESS) {
955 return FAILURE;
956 }
957 zend_hash_move_forward_ex(aht, pos_ptr);
958 } while (1);
959 }
960 return FAILURE;
961} /* }}} */
962
963/* {{{ spl_array_set_array */
964static void spl_array_set_array(zval *object, spl_array_object *intern, zval *array, zend_long ar_flags, bool just_array) {
965 /* Handled by ZPP prior to this, or for __unserialize() before passing to here */
966 ZEND_ASSERT(Z_TYPE_P(array) == IS_ARRAY || Z_TYPE_P(array) == IS_OBJECT);
969 if (Z_TYPE_P(array) == IS_ARRAY) {
970 ZVAL_COPY_VALUE(&garbage, &intern->array);
971 if (Z_REFCOUNT_P(array) == 1) {
972 ZVAL_COPY(&intern->array, array);
973 } else {
974 //??? TODO: try to avoid array duplication
975 ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array)));
976
977 if (intern->is_child) {
978 Z_TRY_DELREF(intern->bucket->val);
979 /*
980 * replace bucket->val with copied array, so the changes between
981 * parent and child object can affect each other.
982 */
983 ZVAL_COPY(&intern->bucket->val, &intern->array);
984 }
985 }
986 } else {
987 if (Z_OBJ_HT_P(array) == &spl_handler_ArrayObject) {
988 ZVAL_COPY_VALUE(&garbage, &intern->array);
989 if (just_array) {
990 spl_array_object *other = Z_SPLARRAY_P(array);
991 ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
992 }
993 if (Z_OBJ_P(object) == Z_OBJ_P(array)) {
994 ar_flags |= SPL_ARRAY_IS_SELF;
995 ZVAL_UNDEF(&intern->array);
996 } else {
997 ar_flags |= SPL_ARRAY_USE_OTHER;
998 ZVAL_COPY(&intern->array, array);
999 }
1000 } else {
1001 zend_object_get_properties_t handler = Z_OBJ_HANDLER_P(array, get_properties);
1002 if (handler != zend_std_get_properties || Z_OBJ_HANDLER_P(array, get_properties_for)) {
1004 "Overloaded object of type %s is not compatible with %s",
1005 ZSTR_VAL(Z_OBJCE_P(array)->name), ZSTR_VAL(intern->std.ce->name));
1007 return;
1008 }
1009 ZVAL_COPY_VALUE(&garbage, &intern->array);
1010 ZVAL_COPY(&intern->array, array);
1011 }
1012 }
1013
1015 intern->ar_flags |= ar_flags;
1016 if (intern->ht_iter != (uint32_t)-1) {
1018 intern->ht_iter = (uint32_t)-1;
1019 }
1020
1022}
1023/* }}} */
1024
1025/* {{{ Constructs a new array object from an array or object. */
1027{
1028 zval *object = ZEND_THIS;
1029 spl_array_object *intern;
1030 zval *array;
1031 zend_long ar_flags = 0;
1032 zend_class_entry *ce_get_iterator = spl_ce_ArrayIterator;
1033
1034 if (ZEND_NUM_ARGS() == 0) {
1035 return; /* nothing to do */
1036 }
1037
1038 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|AlC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
1039 RETURN_THROWS();
1040 }
1041
1042 intern = Z_SPLARRAY_P(object);
1043
1044 if (ZEND_NUM_ARGS() > 2) {
1045 intern->ce_get_iterator = ce_get_iterator;
1046 }
1047
1048 ar_flags &= ~SPL_ARRAY_INT_MASK;
1049
1050 spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
1051}
1052/* }}} */
1053
1054/* {{{ Set the class used in getIterator. */
1055PHP_METHOD(ArrayObject, setIteratorClass)
1056{
1057 zval *object = ZEND_THIS;
1058 spl_array_object *intern = Z_SPLARRAY_P(object);
1059 zend_class_entry *ce_get_iterator = spl_ce_ArrayIterator;
1060
1062 Z_PARAM_CLASS(ce_get_iterator)
1064
1065 intern->ce_get_iterator = ce_get_iterator;
1066}
1067/* }}} */
1068
1069/* {{{ Get the class used in getIterator. */
1070PHP_METHOD(ArrayObject, getIteratorClass)
1071{
1072 zval *object = ZEND_THIS;
1073 spl_array_object *intern = Z_SPLARRAY_P(object);
1074
1076 RETURN_THROWS();
1077 }
1078
1079 zend_string_addref(intern->ce_get_iterator->name);
1081}
1082/* }}} */
1083
1084/* {{{ Get flags */
1086{
1087 zval *object = ZEND_THIS;
1088 spl_array_object *intern = Z_SPLARRAY_P(object);
1089
1091 RETURN_THROWS();
1092 }
1093
1095}
1096/* }}} */
1097
1098/* {{{ Set flags */
1100{
1101 zval *object = ZEND_THIS;
1102 spl_array_object *intern = Z_SPLARRAY_P(object);
1103 zend_long ar_flags = 0;
1104
1105 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ar_flags) == FAILURE) {
1106 RETURN_THROWS();
1107 }
1108
1109 intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
1110}
1111/* }}} */
1112
1113/* {{{ Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
1115{
1116 zval *object = ZEND_THIS, *array;
1117 spl_array_object *intern = Z_SPLARRAY_P(object);
1118
1119 if (zend_parse_parameters(ZEND_NUM_ARGS(), "A", &array) == FAILURE) {
1120 RETURN_THROWS();
1121 }
1122
1123 if (intern->nApplyCount > 0) {
1124 zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
1125 RETURN_THROWS();
1126 }
1127
1128 RETVAL_ARR(zend_array_dup(spl_array_get_hash_table(intern)));
1129 spl_array_set_array(object, intern, array, 0L, 1);
1130}
1131/* }}} */
1132
1133/* {{{ Create a new iterator from a ArrayObject instance */
1135{
1136 zval *object = ZEND_THIS;
1137 spl_array_object *intern = Z_SPLARRAY_P(object);
1138
1140 RETURN_THROWS();
1141 }
1142
1143 RETURN_OBJ(spl_array_object_new_ex(intern->ce_get_iterator, Z_OBJ_P(object), 0));
1144}
1145/* }}} */
1146
1147static zend_long spl_array_object_count_elements_helper(spl_array_object *intern) /* {{{ */
1148{
1149 HashTable *aht = spl_array_get_hash_table(intern);
1150 if (spl_array_is_object(intern)) {
1151 zend_long count = 0;
1153 zval *val;
1154 /* Count public/dynamic properties */
1156 if (Z_TYPE_P(val) == IS_INDIRECT) {
1157 if (Z_TYPE_P(Z_INDIRECT_P(val)) == IS_UNDEF) continue;
1158 if (key && ZSTR_VAL(key)[0] == '\0') continue;
1159 }
1160 count++;
1162 return count;
1163 } else {
1164 return zend_hash_num_elements(aht);
1165 }
1166} /* }}} */
1167
1168static zend_result spl_array_object_count_elements(zend_object *object, zend_long *count) /* {{{ */
1169{
1170 spl_array_object *intern = spl_array_from_obj(object);
1171
1172 if (intern->fptr_count) {
1173 zval rv;
1174 zend_call_method_with_0_params(object, intern->std.ce, &intern->fptr_count, "count", &rv);
1175 if (Z_TYPE(rv) != IS_UNDEF) {
1176 *count = zval_get_long(&rv);
1177 zval_ptr_dtor(&rv);
1178 return SUCCESS;
1179 }
1180 *count = 0;
1181 return FAILURE;
1182 }
1183 *count = spl_array_object_count_elements_helper(intern);
1184 return SUCCESS;
1185} /* }}} */
1186
1187/* {{{ Return the number of elements in the Iterator. */
1189{
1191
1193 RETURN_THROWS();
1194 }
1195
1196 RETURN_LONG(spl_array_object_count_elements_helper(intern));
1197} /* }}} */
1198
1199static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, size_t fname_len, int use_arg) /* {{{ */
1200{
1202 HashTable **ht_ptr = spl_array_get_hash_table_ptr(intern);
1203 HashTable *aht = *ht_ptr;
1204 zval function_name, params[2], *arg = NULL;
1205
1206 ZVAL_STRINGL(&function_name, fname, fname_len);
1207
1208 ZVAL_NEW_EMPTY_REF(&params[0]);
1209 ZVAL_ARR(Z_REFVAL(params[0]), aht);
1210 GC_ADDREF(aht);
1211
1212 if (!use_arg) {
1214 goto exit;
1215 }
1216
1217 intern->nApplyCount++;
1218 call_user_function(EG(function_table), NULL, &function_name, return_value, 1, params);
1219 intern->nApplyCount--;
1220 } else if (use_arg == SPL_ARRAY_METHOD_SORT_FLAGS_ARG) {
1221 zend_long sort_flags = 0;
1222 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &sort_flags) == FAILURE) {
1223 goto exit;
1224 }
1225 ZVAL_LONG(&params[1], sort_flags);
1226 intern->nApplyCount++;
1227 call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params);
1228 intern->nApplyCount--;
1229 } else {
1231 goto exit;
1232 }
1233 ZVAL_COPY_VALUE(&params[1], arg);
1234 intern->nApplyCount++;
1235 call_user_function(EG(function_table), NULL, &function_name, return_value, 2, params);
1236 intern->nApplyCount--;
1237 }
1238
1239exit:
1240 {
1241 zval *ht_zv = Z_REFVAL(params[0]);
1242 zend_array_release(*ht_ptr);
1243 SEPARATE_ARRAY(ht_zv);
1244 *ht_ptr = Z_ARRVAL_P(ht_zv);
1245 ZVAL_NULL(ht_zv);
1246 zval_ptr_dtor(&params[0]);
1247 zend_string_free(Z_STR(function_name));
1248 }
1249} /* }}} */
1250
1251#define SPL_ARRAY_METHOD(cname, fname, use_arg) \
1252PHP_METHOD(cname, fname) \
1253{ \
1254 spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
1255}
1256
1257/* {{{ Sort the entries by values. */
1259
1260/* {{{ Sort the entries by key. */
1262
1263/* {{{ Sort the entries by values user defined function. */
1265
1266/* {{{ Sort the entries by key using user defined function. */
1268
1269/* {{{ Sort the entries by values using "natural order" algorithm. */
1271
1272/* {{{ Sort the entries by key using case insensitive "natural order" algorithm. */
1274
1275/* {{{ Serialize the object */
1277{
1278 zval *object = ZEND_THIS;
1279 spl_array_object *intern = Z_SPLARRAY_P(object);
1280 zval members, flags;
1282 smart_str buf = {0};
1283
1285 RETURN_THROWS();
1286 }
1287
1289
1291
1292 /* storage */
1293 smart_str_appendl(&buf, "x:", 2);
1295
1296 if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
1297 php_var_serialize(&buf, &intern->array, &var_hash);
1298 smart_str_appendc(&buf, ';');
1299 }
1300
1301 /* members */
1302 smart_str_appendl(&buf, "m:", 2);
1303
1304 ZVAL_ARR(&members, zend_std_get_properties_ex(&intern->std));
1305
1306 php_var_serialize(&buf, &members, &var_hash); /* finishes the string */
1307
1308 /* done */
1310
1311 RETURN_STR(smart_str_extract(&buf));
1312} /* }}} */
1313
1314/* {{{ unserialize the object */
1316{
1317 zval *object = ZEND_THIS;
1318 spl_array_object *intern = Z_SPLARRAY_P(object);
1319
1320 char *buf;
1321 size_t buf_len;
1322 const unsigned char *p, *s;
1324 zval *members, *zflags, *array;
1326
1327 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
1328 RETURN_THROWS();
1329 }
1330
1331 if (buf_len == 0) {
1332 return;
1333 }
1334
1335 if (intern->nApplyCount > 0) {
1336 zend_throw_error(NULL, "Modification of ArrayObject during sorting is prohibited");
1337 RETURN_THROWS();
1338 }
1339
1340 /* storage */
1341 s = p = (const unsigned char*)buf;
1343
1344 if (*p!= 'x' || *++p != ':') {
1345 goto outexcept;
1346 }
1347 ++p;
1348
1349 zflags = var_tmp_var(&var_hash);
1350 if (!php_var_unserialize(zflags, &p, s + buf_len, &var_hash) || Z_TYPE_P(zflags) != IS_LONG) {
1351 goto outexcept;
1352 }
1353
1354 --p; /* for ';' */
1355 flags = Z_LVAL_P(zflags);
1356 /* flags needs to be verified and we also need to verify whether the next
1357 * thing we get is ';'. After that we require an 'm' or something else
1358 * where 'm' stands for members and anything else should be an array. If
1359 * neither 'a' or 'm' follows we have an error. */
1360
1361 if (*p != ';') {
1362 goto outexcept;
1363 }
1364 ++p;
1365
1366 if (flags & SPL_ARRAY_IS_SELF) {
1367 /* If IS_SELF is used, the flags are not followed by an array/object */
1369 intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1370 zval_ptr_dtor(&intern->array);
1371 ZVAL_UNDEF(&intern->array);
1372 } else {
1373 if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
1374 goto outexcept;
1375 }
1376
1377 array = var_tmp_var(&var_hash);
1378 if (!php_var_unserialize(array, &p, s + buf_len, &var_hash)
1379 || (Z_TYPE_P(array) != IS_ARRAY && Z_TYPE_P(array) != IS_OBJECT)) {
1380 goto outexcept;
1381 }
1382
1384 intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1385
1386 if (Z_TYPE_P(array) == IS_ARRAY) {
1387 zval_ptr_dtor(&intern->array);
1388 ZVAL_COPY_VALUE(&intern->array, array);
1389 ZVAL_NULL(array);
1390 SEPARATE_ARRAY(&intern->array);
1391 } else {
1392 spl_array_set_array(object, intern, array, 0L, 1);
1393 }
1394
1395 if (*p != ';') {
1396 goto outexcept;
1397 }
1398 ++p;
1399 }
1400
1401 /* members */
1402 if (*p!= 'm' || *++p != ':') {
1403 goto outexcept;
1404 }
1405 ++p;
1406
1407 members = var_tmp_var(&var_hash);
1408 if (!php_var_unserialize(members, &p, s + buf_len, &var_hash) || Z_TYPE_P(members) != IS_ARRAY) {
1409 goto outexcept;
1410 }
1411
1412 /* copy members */
1413 object_properties_load(&intern->std, Z_ARRVAL_P(members));
1414
1415 /* done reading $serialized */
1417 return;
1418
1419outexcept:
1421 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset " ZEND_LONG_FMT " of %zd bytes", (zend_long)((char*)p - buf), buf_len);
1422 RETURN_THROWS();
1423
1424} /* }}} */
1425
1426/* {{{ */
1428{
1430 zval tmp;
1431
1433 RETURN_THROWS();
1434 }
1435
1437
1438 /* flags */
1439 ZVAL_LONG(&tmp, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
1441
1442 /* storage */
1443 if (intern->ar_flags & SPL_ARRAY_IS_SELF) {
1444 ZVAL_NULL(&tmp);
1445 } else {
1446 ZVAL_COPY(&tmp, &intern->array);
1447 }
1449
1450 /* members */
1452 zend_std_get_properties(&intern->std), /* always_duplicate */ 1));
1454
1455 /* iterator class */
1456 if (intern->ce_get_iterator == spl_ce_ArrayIterator) {
1457 ZVAL_NULL(&tmp);
1458 } else {
1459 ZVAL_STR_COPY(&tmp, intern->ce_get_iterator->name);
1460 }
1462}
1463/* }}} */
1464
1465
1466/* {{{ */
1468{
1470 HashTable *data;
1471 zval *flags_zv, *storage_zv, *members_zv, *iterator_class_zv;
1473
1475 RETURN_THROWS();
1476 }
1477
1478 flags_zv = zend_hash_index_find(data, 0);
1479 storage_zv = zend_hash_index_find(data, 1);
1480 members_zv = zend_hash_index_find(data, 2);
1481 iterator_class_zv = zend_hash_index_find(data, 3);
1482
1483 if (!flags_zv || !storage_zv || !members_zv ||
1484 Z_TYPE_P(flags_zv) != IS_LONG || Z_TYPE_P(members_zv) != IS_ARRAY ||
1485 (iterator_class_zv && (Z_TYPE_P(iterator_class_zv) != IS_NULL &&
1486 Z_TYPE_P(iterator_class_zv) != IS_STRING))) {
1488 "Incomplete or ill-typed serialization data", 0);
1489 RETURN_THROWS();
1490 }
1491
1492 flags = Z_LVAL_P(flags_zv);
1494 intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1495
1496 if (flags & SPL_ARRAY_IS_SELF) {
1497 zval_ptr_dtor(&intern->array);
1498 ZVAL_UNDEF(&intern->array);
1499 } else {
1500 if (Z_TYPE_P(storage_zv) != IS_OBJECT && Z_TYPE_P(storage_zv) != IS_ARRAY) {
1501 /* TODO Use UnexpectedValueException instead? And better error message? */
1502 zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object", 0);
1503 RETURN_THROWS();
1504 }
1505 spl_array_set_array(ZEND_THIS, intern, storage_zv, 0L, 1);
1506 }
1507
1508 object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
1509 if (EG(exception)) {
1510 RETURN_THROWS();
1511 }
1512
1513 if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
1514 zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
1515
1516 if (!ce) {
1518 "Cannot deserialize ArrayObject with iterator class '%s'; no such class exists",
1519 ZSTR_VAL(Z_STR_P(iterator_class_zv)));
1520 RETURN_THROWS();
1521 }
1522
1523 if (!instanceof_function(ce, zend_ce_iterator)) {
1525 "Cannot deserialize ArrayObject with iterator class '%s'; this class does not implement the Iterator interface",
1526 ZSTR_VAL(Z_STR_P(iterator_class_zv)));
1527 RETURN_THROWS();
1528 }
1529
1530 intern->ce_get_iterator = ce;
1531 }
1532}
1533/* }}} */
1534
1535/* {{{ */
1537{
1539 RETURN_THROWS();
1540 }
1541
1542 RETURN_ARR(spl_array_get_debug_info(Z_OBJ_P(ZEND_THIS)));
1543} /* }}} */
1544
1545/*** ArrayIterator class ***/
1550
1551static zend_result spl_array_next_ex(spl_array_object *intern, HashTable *aht) /* {{{ */
1552{
1553 uint32_t *pos_ptr = spl_array_get_pos_ptr(aht, intern);
1554
1555 zend_hash_move_forward_ex(aht, pos_ptr);
1556 if (spl_array_is_object(intern)) {
1557 return spl_array_skip_protected(intern, aht);
1558 } else {
1559 return zend_hash_has_more_elements_ex(aht, pos_ptr);
1560 }
1561} /* }}} */
1562
1563static zend_result spl_array_next(spl_array_object *intern) /* {{{ */
1564{
1565 HashTable *aht = spl_array_get_hash_table(intern);
1566
1567 return spl_array_next_ex(intern, aht);
1568
1569} /* }}} */
1570
1571static void spl_array_it_dtor(zend_object_iterator *iter) /* {{{ */
1572{
1573 zval_ptr_dtor(&iter->data);
1574}
1575/* }}} */
1576
1577static zend_result spl_array_it_valid(zend_object_iterator *iter) /* {{{ */
1578{
1579 spl_array_object *object = Z_SPLARRAY_P(&iter->data);
1580 HashTable *aht = spl_array_get_hash_table(object);
1581 return zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, object));
1582}
1583/* }}} */
1584
1585static zval *spl_array_it_get_current_data(zend_object_iterator *iter) /* {{{ */
1586{
1587 spl_array_iterator *array_iter = (spl_array_iterator*)iter;
1588 spl_array_object *object = Z_SPLARRAY_P(&iter->data);
1589 HashTable *aht = spl_array_get_hash_table(object);
1590 zval *data = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, object));
1591 if (data && Z_TYPE_P(data) == IS_INDIRECT) {
1593 }
1594 // ZEND_FE_FETCH_RW converts the value to a reference but doesn't know the source is a property.
1595 // Typed properties must add a type source to the reference, and readonly properties must fail.
1596 if (array_iter->by_ref
1598 && Z_TYPE(object->array) == IS_OBJECT
1599 && !(object->ar_flags & (SPL_ARRAY_IS_SELF|SPL_ARRAY_USE_OTHER))) {
1601 zend_hash_get_current_key_ex(aht, &key, NULL, spl_array_get_pos_ptr(aht, object));
1602 zend_class_entry *ce = Z_OBJCE(object->array);
1605 if (EXPECTED(prop_info != NULL) && ZEND_TYPE_IS_SET(prop_info->type)) {
1606 if (prop_info->flags & ZEND_ACC_READONLY) {
1608 "Cannot acquire reference to readonly property %s::$%s",
1609 ZSTR_VAL(prop_info->ce->name), ZSTR_VAL(key));
1610 return NULL;
1611 }
1614 }
1615 }
1616 return data;
1617}
1618/* }}} */
1619
1620static void spl_array_it_get_current_key(zend_object_iterator *iter, zval *key) /* {{{ */
1621{
1622 spl_array_object *object = Z_SPLARRAY_P(&iter->data);
1623 HashTable *aht = spl_array_get_hash_table(object);
1624 zend_hash_get_current_key_zval_ex(aht, key, spl_array_get_pos_ptr(aht, object));
1625}
1626/* }}} */
1627
1628static void spl_array_it_move_forward(zend_object_iterator *iter) /* {{{ */
1629{
1630 spl_array_object *object = Z_SPLARRAY_P(&iter->data);
1631 HashTable *aht = spl_array_get_hash_table(object);
1632 spl_array_next_ex(object, aht);
1633}
1634/* }}} */
1635
1636static void spl_array_rewind(spl_array_object *intern) /* {{{ */
1637{
1638 HashTable *aht = spl_array_get_hash_table(intern);
1639
1640 if (intern->ht_iter == (uint32_t)-1) {
1641 spl_array_get_pos_ptr(aht, intern);
1642 } else {
1643 zend_hash_internal_pointer_reset_ex(aht, spl_array_get_pos_ptr(aht, intern));
1644 spl_array_skip_protected(intern, aht);
1645 }
1646}
1647/* }}} */
1648
1649static void spl_array_it_rewind(zend_object_iterator *iter) /* {{{ */
1650{
1651 spl_array_object *object = Z_SPLARRAY_P(&iter->data);
1652 spl_array_rewind(object);
1653}
1654/* }}} */
1655
1656static HashTable *spl_array_it_get_gc(zend_object_iterator *iter, zval **table, int *n)
1657{
1658 *n = 1;
1659 *table = &iter->data;
1660 return NULL;
1661}
1662
1663/* iterator handler table */
1664static const zend_object_iterator_funcs spl_array_it_funcs = {
1665 spl_array_it_dtor,
1666 spl_array_it_valid,
1667 spl_array_it_get_current_data,
1668 spl_array_it_get_current_key,
1669 spl_array_it_move_forward,
1670 spl_array_it_rewind,
1671 NULL,
1672 spl_array_it_get_gc,
1673};
1674
1675static zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
1676{
1677 spl_array_iterator *iterator = emalloc(sizeof(spl_array_iterator));
1678 zend_iterator_init(&iterator->it);
1679
1680 ZVAL_OBJ_COPY(&iterator->it.data, Z_OBJ_P(object));
1681 iterator->it.funcs = &spl_array_it_funcs;
1682 iterator->by_ref = by_ref;
1683
1684 return &iterator->it;
1685}
1686/* }}} */
1687
1688/* {{{ Constructs a new array iterator from an array or object. */
1690{
1691 zval *object = ZEND_THIS;
1692 spl_array_object *intern;
1693 zval *array;
1694 zend_long ar_flags = 0;
1695
1696 if (ZEND_NUM_ARGS() == 0) {
1697 return; /* nothing to do */
1698 }
1699
1700 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Al", &array, &ar_flags) == FAILURE) {
1701 RETURN_THROWS();
1702 }
1703
1704 intern = Z_SPLARRAY_P(object);
1705
1706 ar_flags &= ~SPL_ARRAY_INT_MASK;
1707
1708 spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1);
1709}
1710/* }}} */
1711
1712/* {{{ Rewind array back to the start */
1714{
1715 zval *object = ZEND_THIS;
1716 spl_array_object *intern = Z_SPLARRAY_P(object);
1717
1719 RETURN_THROWS();
1720 }
1721
1722 spl_array_rewind(intern);
1723}
1724/* }}} */
1725
1726/* {{{ Seek to position. */
1728{
1729 zend_long opos, position;
1730 zval *object = ZEND_THIS;
1731 spl_array_object *intern = Z_SPLARRAY_P(object);
1732 HashTable *aht = spl_array_get_hash_table(intern);
1733 int result;
1734
1735 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
1736 RETURN_THROWS();
1737 }
1738
1739 opos = position;
1740
1741 if (position >= 0) { /* negative values are not supported */
1742 spl_array_rewind(intern);
1743 result = SUCCESS;
1744
1745 while (position-- > 0 && (result = spl_array_next(intern)) == SUCCESS);
1746
1747 if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS) {
1748 return; /* ok */
1749 }
1750 }
1751 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", opos);
1752} /* }}} */
1753
1754/* {{{ Return current array entry */
1756{
1757 zval *object = ZEND_THIS;
1758 spl_array_object *intern = Z_SPLARRAY_P(object);
1759 zval *entry;
1760 HashTable *aht = spl_array_get_hash_table(intern);
1761
1763 RETURN_THROWS();
1764 }
1765
1766 if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
1767 RETURN_NULL();
1768 }
1769 if (Z_TYPE_P(entry) == IS_INDIRECT) {
1770 entry = Z_INDIRECT_P(entry);
1771 if (Z_TYPE_P(entry) == IS_UNDEF) {
1772 RETURN_NULL();
1773 }
1774 }
1775 RETURN_COPY_DEREF(entry);
1776}
1777/* }}} */
1778
1780{
1781 spl_array_object *intern = Z_SPLARRAY_P(object);
1782 HashTable *aht = spl_array_get_hash_table(intern);
1783
1784 zend_hash_get_current_key_zval_ex(aht, return_value, spl_array_get_pos_ptr(aht, intern));
1785}
1786/* }}} */
1787
1788/* {{{ Return current array key */
1797
1798/* {{{ Move to next entry */
1800{
1801 zval *object = ZEND_THIS;
1802 spl_array_object *intern = Z_SPLARRAY_P(object);
1803 HashTable *aht = spl_array_get_hash_table(intern);
1804
1806 RETURN_THROWS();
1807 }
1808
1809 spl_array_next_ex(intern, aht);
1810}
1811/* }}} */
1812
1813/* {{{ Check whether array contains more entries */
1815{
1816 zval *object = ZEND_THIS;
1817 spl_array_object *intern = Z_SPLARRAY_P(object);
1818 HashTable *aht = spl_array_get_hash_table(intern);
1819
1821 RETURN_THROWS();
1822 }
1823
1824 RETURN_BOOL(zend_hash_has_more_elements_ex(aht, spl_array_get_pos_ptr(aht, intern)) == SUCCESS);
1825}
1826/* }}} */
1827
1828/*** RecursiveArrayIterator methods ***/
1829
1830/* {{{ Check whether current element has children (e.g. is an array) */
1832{
1833 zval *object = ZEND_THIS, *entry;
1834 spl_array_object *intern = Z_SPLARRAY_P(object);
1835 HashTable *aht = spl_array_get_hash_table(intern);
1836
1838 RETURN_THROWS();
1839 }
1840
1841 if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
1843 }
1844
1845 if (Z_TYPE_P(entry) == IS_INDIRECT) {
1846 entry = Z_INDIRECT_P(entry);
1847 }
1848
1849 ZVAL_DEREF(entry);
1850 RETURN_BOOL(Z_TYPE_P(entry) == IS_ARRAY || (Z_TYPE_P(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
1851}
1852/* }}} */
1853
1854static void spl_instantiate_child_arg(zend_class_entry *pce, zval *retval, zval *arg1, zval *arg2) /* {{{ */
1855{
1856 object_init_ex(retval, pce);
1857 spl_array_object *new_intern = Z_SPLARRAY_P(retval);
1858 /*
1859 * set new_intern->is_child is true to indicate that the object was created by
1860 * RecursiveArrayIterator::getChildren() method.
1861 */
1862 new_intern->is_child = true;
1863
1864 /* find the bucket of parent object. */
1865 new_intern->bucket = (Bucket *)((char *)(arg1) - XtOffsetOf(Bucket, val));;
1867}
1868/* }}} */
1869
1870/* {{{ Create a sub iterator for the current element (same class as $this) */
1872{
1873 zval *object = ZEND_THIS, *entry, flags;
1874 spl_array_object *intern = Z_SPLARRAY_P(object);
1875 HashTable *aht = spl_array_get_hash_table(intern);
1876
1878 RETURN_THROWS();
1879 }
1880
1881 if ((entry = zend_hash_get_current_data_ex(aht, spl_array_get_pos_ptr(aht, intern))) == NULL) {
1882 RETURN_NULL();
1883 }
1884
1885 if (Z_TYPE_P(entry) == IS_INDIRECT) {
1886 entry = Z_INDIRECT_P(entry);
1887 }
1888
1889 ZVAL_DEREF(entry);
1890 if (Z_TYPE_P(entry) == IS_OBJECT) {
1891 if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
1892 RETURN_NULL();
1893 }
1894 if (instanceof_function(Z_OBJCE_P(entry), Z_OBJCE_P(ZEND_THIS))) {
1895 RETURN_OBJ_COPY(Z_OBJ_P(entry));
1896 }
1897 }
1898
1899 ZVAL_LONG(&flags, intern->ar_flags);
1900 spl_instantiate_child_arg(Z_OBJCE_P(ZEND_THIS), return_value, entry, &flags);
1901}
1902/* }}} */
1903
1904/* {{{ PHP_MINIT_FUNCTION(spl_array) */
1906{
1908 spl_ce_ArrayObject->create_object = spl_array_object_new;
1909 spl_ce_ArrayObject->default_object_handlers = &spl_handler_ArrayObject;
1910
1911 memcpy(&spl_handler_ArrayObject, &std_object_handlers, sizeof(zend_object_handlers));
1912
1913 spl_handler_ArrayObject.offset = XtOffsetOf(spl_array_object, std);
1914
1915 spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
1916 spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
1917 spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
1918 spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
1919 spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
1920 spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
1921
1922 spl_handler_ArrayObject.get_properties_for = spl_array_get_properties_for;
1923 spl_handler_ArrayObject.get_gc = spl_array_get_gc;
1924 spl_handler_ArrayObject.read_property = spl_array_read_property;
1925 spl_handler_ArrayObject.write_property = spl_array_write_property;
1926 spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
1927 spl_handler_ArrayObject.has_property = spl_array_has_property;
1928 spl_handler_ArrayObject.unset_property = spl_array_unset_property;
1929
1930 spl_handler_ArrayObject.compare = spl_array_compare_objects;
1931 spl_handler_ArrayObject.free_obj = spl_array_object_free_storage;
1932
1934 spl_ce_ArrayIterator->create_object = spl_array_object_new;
1935 spl_ce_ArrayIterator->default_object_handlers = &spl_handler_ArrayObject;
1936 spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
1937
1938 spl_ce_RecursiveArrayIterator = register_class_RecursiveArrayIterator(spl_ce_ArrayIterator, spl_ce_RecursiveIterator);
1939 spl_ce_RecursiveArrayIterator->create_object = spl_array_object_new;
1940 spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
1941
1942 return SUCCESS;
1943}
1944/* }}} */
bool exception
Definition assert.c:30
rewind($stream)
count(Countable|array $value, int $mode=COUNT_NORMAL)
natcasesort(array &$array)
natsort(array &$array)
ksort(array &$array, int $flags=SORT_REGULAR)
uasort(array &$array, callable $callback)
asort(array &$array, int $flags=SORT_REGULAR)
uksort(array &$array, callable $callback)
char s[4]
Definition cdf.c:77
zend_ffi_type * type
Definition ffi.c:3812
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
zval * arg
Definition ffi.c:3975
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
zend_long offset
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
#define next(ls)
Definition minilua.c:2661
#define PHP_MINIT_FUNCTION
Definition php.h:400
#define PHP_METHOD
Definition php.h:365
#define PHPAPI
Definition php.h:71
unsigned char key[REFLECTION_KEY_LEN]
#define PHP_VAR_UNSERIALIZE_DESTROY(d)
Definition php_var.h:59
struct php_unserialize_data * php_unserialize_data_t
Definition php_var.h:32
struct php_serialize_data * php_serialize_data_t
Definition php_var.h:31
#define PHP_VAR_UNSERIALIZE_INIT(d)
Definition php_var.h:56
PHPAPI zval * var_tmp_var(php_unserialize_data_t *var_hashx)
PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash)
#define PHP_VAR_SERIALIZE_INIT(d)
Definition php_var.h:50
PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data)
Definition var.c:1319
#define PHP_VAR_SERIALIZE_DESTROY(d)
Definition php_var.h:53
HashTable seek
Definition phpdbg.h:233
zend_constant * data
zval * current
Definition session.c:1024
zval rv
Definition session.c:1024
p
Definition session.c:1105
php_unserialize_data_t var_hash
Definition session.c:964
void spl_array_iterator_append(zval *object, zval *append_value)
Definition spl_array.c:716
PHPAPI zend_class_entry * spl_ce_RecursiveArrayIterator
Definition spl_array.c:35
PHPAPI zend_class_entry * spl_ce_ArrayIterator
Definition spl_array.c:34
#define Z_SPLARRAY_P(zv)
Definition spl_array.c:63
void spl_array_iterator_key(zval *object, zval *return_value)
Definition spl_array.c:1779
struct _spl_array_object spl_array_object
struct _spl_array_iterator spl_array_iterator
PHPAPI zend_class_entry * spl_ce_ArrayObject
Definition spl_array.c:39
#define SPL_ARRAY_METHOD(cname, fname, use_arg)
Definition spl_array.c:1251
#define SPL_ARRAY_IS_SELF
Definition spl_array.h:25
#define SPL_ARRAY_CLONE_MASK
Definition spl_array.h:28
#define SPL_ARRAY_METHOD_NO_ARG
Definition spl_array.h:30
#define SPL_ARRAY_METHOD_SORT_FLAGS_ARG
Definition spl_array.h:32
#define SPL_ARRAY_STD_PROP_LIST
Definition spl_array.h:22
#define SPL_ARRAY_ARRAY_AS_PROPS
Definition spl_array.h:23
#define SPL_ARRAY_USE_OTHER
Definition spl_array.h:26
#define SPL_ARRAY_CHILD_ARRAYS_ONLY
Definition spl_array.h:24
#define SPL_ARRAY_INT_MASK
Definition spl_array.h:27
#define SPL_ARRAY_METHOD_CALLBACK_ARG
Definition spl_array.h:31
PHPAPI zend_class_entry * spl_ce_UnexpectedValueException
PHPAPI zend_class_entry * spl_ce_OutOfBoundsException
PHPAPI zend_class_entry * spl_ce_InvalidArgumentException
void spl_set_private_debug_info_property(const zend_class_entry *ce, const char *property, size_t property_len, HashTable *debug_info, zval *value)
PHPAPI zend_class_entry * spl_ce_RecursiveIterator
PHPAPI zend_class_entry * spl_ce_SeekableIterator
zval val
Definition zend_types.h:381
zend_object_iterator it
Definition spl_array.c:1547
unsigned char nApplyCount
Definition spl_array.c:46
zend_function * fptr_offset_del
Definition spl_array.c:52
uint32_t ht_iter
Definition spl_array.c:44
Bucket * bucket
Definition spl_array.c:48
zend_function * fptr_offset_get
Definition spl_array.c:49
zend_function * fptr_offset_set
Definition spl_array.c:50
zend_function * fptr_count
Definition spl_array.c:53
zend_class_entry * ce_get_iterator
Definition spl_array.c:54
zend_object std
Definition spl_array.c:55
HashTable * sentinel_array
Definition spl_array.c:43
zend_function * fptr_offset_has
Definition spl_array.c:51
zend_string * name
Definition zend.h:149
zend_function * constructor
Definition zend.h:172
HashTable function_table
Definition zend.h:163
const zend_object_iterator_funcs * funcs
zend_class_entry * ce
Definition zend_types.h:560
HashTable * properties
Definition zend_types.h:562
zend_string * key
Definition spl_array.c:264
zend_ulong h
Definition spl_array.c:265
bool release_key
Definition spl_array.c:266
zend_class_entry * scope
struct _zend_function::@236135173067030250234125302313220025134003177336 common
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
ZEND_API ZEND_COLD void zend_illegal_container_offset(const zend_string *container, const zval *offset, int type)
Definition zend.c:1802
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API void object_properties_load(zend_object *object, HashTable *properties)
Definition zend_API.c:1728
#define RETURN_COPY_DEREF(zv)
Definition zend_API.h:1056
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
ZEND_API void zend_call_known_instance_method_with_2_params(zend_function *fn, zend_object *object, zval *retval_ptr, zval *param1, zval *param2)
#define RETURN_OBJ(r)
Definition zend_API.h:1052
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define RETURN_NULL()
Definition zend_API.h:1036
#define RETURN_ARR(r)
Definition zend_API.h:1050
#define zend_parse_parameters_none()
Definition zend_API.h:353
#define RETVAL_ARR(r)
Definition zend_API.h:1024
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_CLASS(dest)
Definition zend_API.h:1740
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_OBJ_COPY(r)
Definition zend_API.h:1053
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETURN_STR(s)
Definition zend_API.h:1039
#define ZEND_THIS
Definition zend_API.h:523
#define call_user_function(function_table, object, function_name, retval_ptr, param_count, params)
Definition zend_API.h:687
#define ZVAL_STRINGL(z, s, l)
Definition zend_API.h:952
#define array_init(arg)
Definition zend_API.h:537
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
exit(string|int $status=0)
zend_string_release_ex(func->internal_function.function_name, 0)
#define BP_VAR_R
#define BP_VAR_W
#define ZEND_ACC_READONLY
struct _zend_property_info zend_property_info
#define BP_VAR_RW
#define BP_VAR_IS
#define BP_VAR_UNSET
#define E_WARNING
Definition zend_errors.h:24
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim)
ZEND_API zend_class_entry * zend_lookup_class(zend_string *name)
#define ZEND_REF_ADD_TYPE_SOURCE(ref, source)
union _zend_function zend_function
#define EG(v)
ZEND_API HashTable *ZEND_FASTCALL zend_proptable_to_symtable(HashTable *ht, bool always_duplicate)
Definition zend_hash.c:3387
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2773
ZEND_API uint32_t ZEND_FASTCALL zend_hash_iterator_add(HashTable *ht, HashPosition pos)
Definition zend_hash.c:537
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos)
Definition zend_hash.c:2846
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2733
ZEND_API zval *ZEND_FASTCALL zend_hash_get_current_data_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2915
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1692
ZEND_API zval *ZEND_FASTCALL zend_hash_update_ind(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1002
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, const HashPosition *pos)
Definition zend_hash.c:2870
ZEND_API zval *ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1219
ZEND_API void ZEND_FASTCALL zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor)
Definition zend_hash.c:2240
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:997
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
Definition zend_hash.c:1534
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
ZEND_API void ZEND_FASTCALL zend_hash_iterator_del(uint32_t idx)
Definition zend_hash.c:649
ZEND_API HashPosition ZEND_FASTCALL zend_hash_get_current_pos(const HashTable *ht)
Definition zend_hash.c:512
#define HASH_KEY_IS_STRING
Definition zend_hash.h:29
#define zend_new_array(size)
Definition zend_hash.h:338
#define ZEND_HANDLE_NUMERIC(key, idx)
Definition zend_hash.h:420
#define ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _key, _val)
Definition zend_hash.h:1166
#define HT_FLAGS(ht)
Definition zend_hash.h:50
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define HASH_FLAG_HAS_EMPTY_IND
Definition zend_hash.h:44
ZEND_API zend_class_entry * zend_ce_countable
ZEND_API zend_class_entry * zend_ce_iterator
ZEND_API zend_class_entry * zend_ce_serializable
ZEND_API zend_class_entry * zend_ce_arrayaccess
ZEND_API zend_class_entry * zend_ce_aggregate
ZEND_API void zend_iterator_init(zend_object_iterator *iter)
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
ZEND_API zend_object * zend_lazy_object_init(zend_object *obj)
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API zval * zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *name, int type, void **cache_slot)
ZEND_API HashTable * zend_std_get_properties_for(zend_object *obj, zend_prop_purpose purpose)
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has_set_exists, void **cache_slot)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API zval * zend_std_write_property(zend_object *zobj, zend_string *name, zval *value, void **cache_slot)
ZEND_API zend_property_info * zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent)
ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void **cache_slot)
ZEND_API zval * zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv)
ZEND_API int zend_std_compare_objects(zval *o1, zval *o2)
#define ZEND_WRONG_PROPERTY_INFO
enum _zend_prop_purpose zend_prop_purpose
HashTable *(* zend_object_get_properties_t)(zend_object *object)
@ ZEND_PROP_PURPOSE_ARRAY_CAST
@ ZEND_PROP_PURPOSE_VAR_EXPORT
@ ZEND_PROP_PURPOSE_JSON
#define ZEND_PROPERTY_EXISTS
#define ZEND_COMPARE_OBJECTS_FALLBACK(op1, op2)
ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
ZEND_API zend_string *ZEND_FASTCALL zend_long_to_str(zend_long num)
ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op)
ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2)
#define zend_never_inline
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define zend_always_inline
#define XtOffsetOf(s_type, field)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define ZSTR_KNOWN(idx)
#define ZSTR_EMPTY_ALLOC()
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define Z_OBJ_HANDLER_P(zv_p, hf)
Definition zend_types.h:996
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZVAL_STR(z, s)
#define Z_ISREF_P(zval_p)
Definition zend_types.h:954
#define Z_TRY_ADDREF_P(pz)
#define ZVAL_NEW_EMPTY_REF(z)
#define ZVAL_UNDEF(z)
#define GC_SET_REFCOUNT(p, rc)
Definition zend_types.h:708
#define IS_FALSE
Definition zend_types.h:602
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define ZVAL_DEREF(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
#define ZVAL_STR_COPY(z, s)
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_RESOURCE
Definition zend_types.h:609
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define Z_OBJ_HT_P(zval_p)
Definition zend_types.h:993
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define ZVAL_NEW_REF(z, r)
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_DELREF(p)
Definition zend_types.h:710
#define GC_FLAGS(p)
Definition zend_types.h:756
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_REFVAL(zval)
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJCE_P(zval_p)
@ FAILURE
Definition zend_types.h:61
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_ARR(z, a)
void(* copy_ctor_func_t)(zval *pElement)
Definition zend_types.h:108
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
#define IS_REFERENCE
Definition zend_types.h:610
#define ZVAL_COPY(z, v)
struct _Bucket Bucket
#define Z_INDIRECT_P(zval_p)
#define Z_REF_P(zval_p)
#define ZVAL_OBJ_COPY(z, o)
#define Z_REFCOUNT_P(pz)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define IS_ARRAY_IMMUTABLE
Definition zend_types.h:823
#define Z_RES_P(zval_p)
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define SEPARATE_ARRAY(zv)
#define GC_REFCOUNT(p)
Definition zend_types.h:707
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_DVAL_P(zval_p)
Definition zend_types.h:969
#define IS_INDIRECT
Definition zend_types.h:623
#define Z_TRY_DELREF(z)
#define Z_ARRVAL(zval)
Definition zend_types.h:986
#define Z_ARR_P(zval_p)
Definition zend_types.h:984
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define Z_OBJCE(zval)
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
ZEND_API void zval_add_ref(zval *p)
zval retval
zval * return_value
zval * arg1
zval * arg2
zend_property_info * prop_info
zend_string * name
fbc internal_function handler(call, ret)
bool result
object
zend_refcounted * garbage
zval * ret
value