php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
spl_observer.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 | Etienne Kneuss <colder@php.net> |
15 +----------------------------------------------------------------------+
16 */
17
18#ifdef HAVE_CONFIG_H
19# include "config.h"
20#endif
21
22#include "php.h"
23#include "ext/standard/php_array.h" /* For PHP_COUNT_* constants */
25#include "zend_smart_str.h"
26#include "zend_interfaces.h"
27#include "zend_exceptions.h"
28
29#include "php_spl.h" /* For php_spl_object_hash() */
30#include "spl_observer.h"
32#include "spl_iterators.h"
33#include "spl_exceptions.h"
34#include "spl_functions.h" /* For spl_set_private_debug_info_property() */
35
40
41static zend_object_handlers spl_handler_SplObjectStorage;
42
43/* Bit flags for marking internal functionality overridden by SplObjectStorage subclasses. */
44#define SOS_OVERRIDDEN_READ_DIMENSION 1
45#define SOS_OVERRIDDEN_WRITE_DIMENSION 2
46#define SOS_OVERRIDDEN_UNSET_DIMENSION 4
47
48typedef struct _spl_SplObjectStorage { /* {{{ */
52 /* In SplObjectStorage, flags is a hidden implementation detail to optimize ArrayAccess handlers.
53 * In MultipleIterator on a different class hierarchy, flags is a user settable value controlling iteration behavior. */
58
59/* {{{ storage is an assoc array of [zend_object*]=>[zval *obj, zval *inf] */
64
65static inline spl_SplObjectStorage *spl_object_storage_from_obj(zend_object *obj) /* {{{ */ {
66 return (spl_SplObjectStorage*)((char*)(obj) - XtOffsetOf(spl_SplObjectStorage, std));
67}
68/* }}} */
69
70#define Z_SPLOBJSTORAGE_P(zv) spl_object_storage_from_obj(Z_OBJ_P((zv)))
71
72static void spl_SplObjectStorage_free_storage(zend_object *object) /* {{{ */
73{
74 spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
75
76 zend_object_std_dtor(&intern->std);
77
78 zend_hash_destroy(&intern->storage);
79} /* }}} */
80
81static zend_result spl_object_storage_get_hash(zend_hash_key *key, spl_SplObjectStorage *intern, zend_object *obj) {
82 if (UNEXPECTED(intern->fptr_get_hash)) {
83 zval param;
84 zval rv;
85 ZVAL_OBJ(&param, obj);
86 zend_call_method_with_1_params(&intern->std, intern->std.ce, &intern->fptr_get_hash, "getHash", &rv, &param);
87 if (UNEXPECTED(Z_ISUNDEF(rv))) {
88 /* An exception has occurred */
89 return FAILURE;
90 } else {
91 /* TODO PHP 9: Remove this as this will be enforced from the return type */
92 if (UNEXPECTED(Z_TYPE(rv) != IS_STRING)) {
93 zend_type_error("%s::getHash(): Return value must be of type string, %s returned",
96 return FAILURE;
97 } else {
98 key->key = Z_STR(rv);
99 return SUCCESS;
100 }
101 }
102 } else {
103 key->key = NULL;
104 key->h = obj->handle;
105 return SUCCESS;
106 }
107}
108
109static void spl_object_storage_free_hash(spl_SplObjectStorage *intern, zend_hash_key *key) {
110 if (key->key) {
112 }
113}
114
115static void spl_object_storage_dtor(zval *element) /* {{{ */
116{
118 if (el) {
119 zend_object_release(el->obj);
120 zval_ptr_dtor(&el->inf);
121 efree(el);
122 }
123} /* }}} */
124
125static spl_SplObjectStorageElement* spl_object_storage_get(spl_SplObjectStorage *intern, zend_hash_key *key) /* {{{ */
126{
127 if (key->key) {
128 return zend_hash_find_ptr(&intern->storage, key->key);
129 } else {
130 return zend_hash_index_find_ptr(&intern->storage, key->h);
131 }
132} /* }}} */
133
134static spl_SplObjectStorageElement *spl_object_storage_create_element(zend_object *obj, zval *inf) /* {{{ */
135{
137 pelement->obj = obj;
138 GC_ADDREF(obj);
139 if (inf) {
140 ZVAL_COPY(&pelement->inf, inf);
141 } else {
142 ZVAL_NULL(&pelement->inf);
143 }
144 return pelement;
145} /* }}} */
146
147/* A faster version of spl_object_storage_attach used when neither SplObjectStorage->getHash nor SplObjectStorage->offsetSet is overridden. */
148static spl_SplObjectStorageElement *spl_object_storage_attach_handle(spl_SplObjectStorage *intern, zend_object *obj, zval *inf) /* {{{ */
149{
150 uint32_t handle = obj->handle;
151 zval *entry_zv = zend_hash_index_lookup(&intern->storage, handle);
154
155 if (Z_TYPE_P(entry_zv) != IS_NULL) {
156 zval zv_inf;
157 ZEND_ASSERT(Z_TYPE_P(entry_zv) == IS_PTR);
158 pelement = Z_PTR_P(entry_zv);
159 ZVAL_COPY_VALUE(&zv_inf, &pelement->inf);
160 if (inf) {
161 ZVAL_COPY(&pelement->inf, inf);
162 } else {
163 ZVAL_NULL(&pelement->inf);
164 }
165 /* Call the old value's destructor last, in case it moves the entry */
166 zval_ptr_dtor(&zv_inf);
167 return pelement;
168 }
169
170 /* NULL initialization necessary because `spl_object_storage_create_element` could bail out due to OOM. */
171 ZVAL_PTR(entry_zv, NULL);
172 pelement = spl_object_storage_create_element(obj, inf);
173 Z_PTR_P(entry_zv) = pelement;
174 return pelement;
175} /* }}} */
176
177static spl_SplObjectStorageElement *spl_object_storage_attach(spl_SplObjectStorage *intern, zend_object *obj, zval *inf) /* {{{ */
178{
180 return spl_object_storage_attach_handle(intern, obj, inf);
181 }
182 /* getHash or offsetSet is overridden. */
183
184 spl_SplObjectStorageElement *pelement, element;
186 if (spl_object_storage_get_hash(&key, intern, obj) == FAILURE) {
187 return NULL;
188 }
189
190 pelement = spl_object_storage_get(intern, &key);
191
192 if (pelement) {
193 zval zv_inf;
194 ZVAL_COPY_VALUE(&zv_inf, &pelement->inf);
195 if (inf) {
196 ZVAL_COPY(&pelement->inf, inf);
197 } else {
198 ZVAL_NULL(&pelement->inf);
199 }
200 spl_object_storage_free_hash(intern, &key);
201 /* Call the old value's destructor last, in case it moves the entry */
202 zval_ptr_dtor(&zv_inf);
203 return pelement;
204 }
205
206 element.obj = obj;
207 GC_ADDREF(obj);
208 if (inf) {
209 ZVAL_COPY(&element.inf, inf);
210 } else {
211 ZVAL_NULL(&element.inf);
212 }
213 if (key.key) {
214 pelement = zend_hash_update_mem(&intern->storage, key.key, &element, sizeof(spl_SplObjectStorageElement));
215 } else {
216 pelement = zend_hash_index_update_mem(&intern->storage, key.h, &element, sizeof(spl_SplObjectStorageElement));
217 }
218 spl_object_storage_free_hash(intern, &key);
219 return pelement;
220} /* }}} */
221
222static zend_result spl_object_storage_detach(spl_SplObjectStorage *intern, zend_object *obj) /* {{{ */
223{
225 return zend_hash_index_del(&intern->storage, obj->handle);
226 }
229 if (spl_object_storage_get_hash(&key, intern, obj) == FAILURE) {
230 return ret;
231 }
232 if (key.key) {
233 ret = zend_hash_del(&intern->storage, key.key);
234 } else {
235 ret = zend_hash_index_del(&intern->storage, key.h);
236 }
237 spl_object_storage_free_hash(intern, &key);
238
239 return ret;
240} /* }}}*/
241
242static void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorage *other) { /* {{{ */
244
245 ZEND_HASH_FOREACH_PTR(&other->storage, element) {
246 spl_object_storage_attach(intern, element->obj, &element->inf);
248
249 intern->index = 0;
250} /* }}} */
251
252#define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zstr_method) \
253 (class_type->arrayaccess_funcs_ptr && class_type->arrayaccess_funcs_ptr->zstr_method)
254
255static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend_object *orig) /* {{{ */
256{
257 spl_SplObjectStorage *intern;
258 zend_class_entry *parent = class_type;
259
260 intern = emalloc(sizeof(spl_SplObjectStorage) + zend_object_properties_size(parent));
261 memset(intern, 0, sizeof(spl_SplObjectStorage) - sizeof(zval));
262 intern->pos = 0;
263
264 zend_object_std_init(&intern->std, class_type);
265 object_properties_init(&intern->std, class_type);
266
267 zend_hash_init(&intern->storage, 0, NULL, spl_object_storage_dtor, 0);
268
269 while (parent) {
270 if (parent == spl_ce_SplObjectStorage) {
271 /* Possible optimization: Cache these results with a map from class entry to IS_NULL/IS_PTR.
272 * Or maybe just a single item with the result for the most recently loaded subclass. */
273 if (class_type != spl_ce_SplObjectStorage) {
274 zend_function *get_hash = zend_hash_str_find_ptr(&class_type->function_table, "gethash", sizeof("gethash") - 1);
275 if (get_hash->common.scope != spl_ce_SplObjectStorage) {
276 intern->fptr_get_hash = get_hash;
277 }
278 if (intern->fptr_get_hash != NULL ||
279 SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetget) ||
280 SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetexists)) {
282 }
283
284 if (intern->fptr_get_hash != NULL ||
285 SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetset)) {
287 }
288
289 if (intern->fptr_get_hash != NULL ||
290 SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetunset)) {
292 }
293 }
294 break;
295 }
296
297 parent = parent->parent;
298 }
299
300 if (orig) {
301 spl_SplObjectStorage *other = spl_object_storage_from_obj(orig);
302 spl_object_storage_addall(intern, other);
303 }
304
305 return &intern->std;
306}
307/* }}} */
308
309/* {{{ spl_object_storage_clone */
310static zend_object *spl_object_storage_clone(zend_object *old_object)
311{
312 zend_object *new_object;
313
314 new_object = spl_object_storage_new_ex(old_object->ce, old_object);
315
316 zend_objects_clone_members(new_object, old_object);
317
318 return new_object;
319}
320/* }}} */
321
322static inline HashTable* spl_object_storage_debug_info(zend_object *obj) /* {{{ */
323{
324 spl_SplObjectStorage *intern = spl_object_storage_from_obj(obj);
326 HashTable *props;
327 zval tmp, storage;
328 HashTable *debug_info;
329
330 props = obj->handlers->get_properties(obj);
331
332 debug_info = zend_new_array(zend_hash_num_elements(props) + 1);
333 zend_hash_copy(debug_info, props, (copy_ctor_func_t)zval_add_ref);
334
335 array_init(&storage);
336
337 ZEND_HASH_FOREACH_PTR(&intern->storage, element) {
338 array_init(&tmp);
339 zval obj;
340 ZVAL_OBJ_COPY(&obj, element->obj);
341 add_assoc_zval_ex(&tmp, "obj", sizeof("obj") - 1, &obj);
342 Z_TRY_ADDREF(element->inf);
343 add_assoc_zval_ex(&tmp, "inf", sizeof("inf") - 1, &element->inf);
346
347 spl_set_private_debug_info_property(spl_ce_SplObjectStorage, "storage", strlen("storage"), debug_info, &storage);
348
349 return debug_info;
350}
351/* }}} */
352
353/* overridden for garbage collection */
354static HashTable *spl_object_storage_get_gc(zend_object *obj, zval **table, int *n) /* {{{ */
355{
356 spl_SplObjectStorage *intern = spl_object_storage_from_obj(obj);
359
360 ZEND_HASH_FOREACH_PTR(&intern->storage, element) {
361 zend_get_gc_buffer_add_obj(gc_buffer, element->obj);
362 zend_get_gc_buffer_add_zval(gc_buffer, &element->inf);
364
365 zend_get_gc_buffer_use(gc_buffer, table, n);
366 return zend_std_get_properties(obj);
367}
368/* }}} */
369
370static int spl_object_storage_compare_info(zval *e1, zval *e2) /* {{{ */
371{
374
375 return zend_compare(&s1->inf, &s2->inf);
376}
377/* }}} */
378
379static int spl_object_storage_compare_objects(zval *o1, zval *o2) /* {{{ */
380{
381 zend_object *zo1;
382 zend_object *zo2;
383
385
386 zo1 = (zend_object *)Z_OBJ_P(o1);
387 zo2 = (zend_object *)Z_OBJ_P(o2);
388
389 if (zo1->ce != spl_ce_SplObjectStorage || zo2->ce != spl_ce_SplObjectStorage) {
390 return ZEND_UNCOMPARABLE;
391 }
392
393 return zend_hash_compare(&(Z_SPLOBJSTORAGE_P(o1))->storage, &(Z_SPLOBJSTORAGE_P(o2))->storage, (compare_func_t)spl_object_storage_compare_info, 0);
394}
395/* }}} */
396
397/* {{{ spl_array_object_new */
398static zend_object *spl_SplObjectStorage_new(zend_class_entry *class_type)
399{
400 return spl_object_storage_new_ex(class_type, NULL);
401}
402/* }}} */
403
404/* Returns true if the SplObjectStorage contains an entry for getHash(obj), even if the corresponding value is null. */
405static bool spl_object_storage_contains(spl_SplObjectStorage *intern, zend_object *obj) /* {{{ */
406{
407 if (EXPECTED(!intern->fptr_get_hash)) {
408 return zend_hash_index_find(&intern->storage, obj->handle) != NULL;
409 }
411 if (spl_object_storage_get_hash(&key, intern, obj) == FAILURE) {
412 return true;
413 }
414
415 ZEND_ASSERT(key.key);
416 bool found = zend_hash_exists(&intern->storage, key.key);
418
419 return found;
420} /* }}} */
421
422/* {{{ Attaches an object to the storage if not yet contained */
424{
425 zend_object *obj;
426 zval *inf = NULL;
427
429
431 Z_PARAM_OBJ(obj)
433 Z_PARAM_ZVAL(inf)
435 spl_object_storage_attach(intern, obj, inf);
436} /* }}} */
437
438// todo: make spl_object_storage_has_dimension return bool as well
439static int spl_object_storage_has_dimension(zend_object *object, zval *offset, int check_empty)
440{
441 spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
443 /* Can't optimize empty()/isset() check if getHash, offsetExists, or offsetGet is overridden */
444 return zend_std_has_dimension(object, offset, check_empty);
445 }
446 spl_SplObjectStorageElement *element = zend_hash_index_find_ptr(&intern->storage, Z_OBJ_HANDLE_P(offset));
447 if (!element) {
448 return 0;
449 }
450
451 if (check_empty) {
452 return i_zend_is_true(&element->inf);
453 }
454 /* NOTE: SplObjectStorage->offsetExists() is an alias of SplObjectStorage->contains(), so this returns true even if the value is null. */
455 return 1;
456}
457
458static zval *spl_object_storage_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
459{
460 spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
462 /* Can't optimize it if getHash, offsetExists, or offsetGet is overridden */
463 return zend_std_read_dimension(object, offset, type, rv);
464 }
465 spl_SplObjectStorageElement *element = zend_hash_index_find_ptr(&intern->storage, Z_OBJ_HANDLE_P(offset));
466
467 if (!element) {
468 if (type == BP_VAR_IS) {
469 return &EG(uninitialized_zval);
470 }
472 return NULL;
473 } else {
474 /* This deliberately returns a non-reference, even for BP_VAR_W and BP_VAR_RW, to behave the same way as SplObjectStorage did when using the default zend_std_read_dimension behavior.
475 * i.e. This prevents taking a reference to an entry of SplObjectStorage because offsetGet would return a non-reference. */
476 ZVAL_COPY_DEREF(rv, &element->inf);
477 return rv;
478 }
479}
480
481static void spl_object_storage_write_dimension(zend_object *object, zval *offset, zval *inf)
482{
483 spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
485 zend_std_write_dimension(object, offset, inf);
486 return;
487 }
488 spl_object_storage_attach_handle(intern, Z_OBJ_P(offset), inf);
489}
490
491static void spl_object_storage_unset_dimension(zend_object *object, zval *offset)
492{
493 spl_SplObjectStorage *intern = spl_object_storage_from_obj(object);
496 return;
497 }
499}
500
501/* {{{ Detaches an object from the storage */
503{
504 zend_object *obj;
506
508 Z_PARAM_OBJ(obj)
510 spl_object_storage_detach(intern, obj);
511
513 intern->index = 0;
514} /* }}} */
515
516/* {{{ Returns the hash of an object */
518{
519 zend_object *obj;
520
522 Z_PARAM_OBJ(obj)
524
526
527} /* }}} */
528
529/* {{{ Returns associated information for a stored object */
531{
532 zend_object *obj;
536
538 Z_PARAM_OBJ(obj)
540
541 if (spl_object_storage_get_hash(&key, intern, obj) == FAILURE) {
542 RETURN_NULL();
543 }
544
545 element = spl_object_storage_get(intern, &key);
546 spl_object_storage_free_hash(intern, &key);
547
548 if (!element) {
550 } else {
551 RETURN_COPY_DEREF(&element->inf);
552 }
553} /* }}} */
554
555/* {{{ Add all elements contained in $os */
557{
558 zval *obj;
561
564 }
565
566 other = Z_SPLOBJSTORAGE_P(obj);
567
568 spl_object_storage_addall(intern, other);
569
570 RETURN_LONG(zend_hash_num_elements(&intern->storage));
571} /* }}} */
572
573/* {{{ Remove all elements contained in $os */
575{
576 zval *obj;
580
583 }
584
585 other = Z_SPLOBJSTORAGE_P(obj);
586
587 zend_hash_internal_pointer_reset(&other->storage);
588 while ((element = zend_hash_get_current_data_ptr(&other->storage)) != NULL) {
589 if (spl_object_storage_detach(intern, element->obj) == FAILURE) {
590 zend_hash_move_forward(&other->storage);
591 }
592 }
593
595 intern->index = 0;
596
597 RETURN_LONG(zend_hash_num_elements(&intern->storage));
598} /* }}} */
599
600/* {{{ Remove elements not common to both this SplObjectStorage instance and $os */
602{
603 zval *obj;
607
610 }
611
612 other = Z_SPLOBJSTORAGE_P(obj);
613
614 ZEND_HASH_FOREACH_PTR(&intern->storage, element) {
615 if (!spl_object_storage_contains(other, element->obj)) {
616 spl_object_storage_detach(intern, element->obj);
617 }
619
621 intern->index = 0;
622
623 RETURN_LONG(zend_hash_num_elements(&intern->storage));
624}
625/* }}} */
626
627/* {{{ Determine whether an object is contained in the storage */
629{
630 zend_object *obj;
632
634 Z_PARAM_OBJ(obj)
636 RETURN_BOOL(spl_object_storage_contains(intern, obj));
637} /* }}} */
638
639/* {{{ Determine number of objects in storage */
641{
644
647 }
648
649 if (mode == PHP_COUNT_RECURSIVE) {
651 }
652
653 RETURN_LONG(zend_hash_num_elements(&intern->storage));
654} /* }}} */
655
656/* {{{ Rewind to first position */
658{
660
663 }
664
666 intern->index = 0;
667} /* }}} */
668
669/* {{{ Returns whether current position is valid */
671{
673
676 }
677
678 RETURN_BOOL(zend_hash_has_more_elements_ex(&intern->storage, &intern->pos) == SUCCESS);
679} /* }}} */
680
681/* {{{ Returns current key */
683{
685
688 }
689
690 RETURN_LONG(intern->index);
691} /* }}} */
692
693/* {{{ Returns current element */
695{
698
701 }
702
703 if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) == NULL) {
704 zend_throw_exception(spl_ce_RuntimeException, "Called current() on invalid iterator", 0);
706 }
707 ZVAL_OBJ_COPY(return_value, element->obj);
708} /* }}} */
709
710/* {{{ Returns associated information to current element */
712{
715
718 }
719
720 if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) == NULL) {
721 RETURN_NULL();
722 }
723 ZVAL_COPY(return_value, &element->inf);
724} /* }}} */
725
726/* {{{ Sets associated information of current element to $inf */
728{
731 zval *inf;
732
733 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &inf) == FAILURE) {
735 }
736
737 if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) == NULL) {
738 RETURN_NULL();
739 }
741 ZVAL_COPY_VALUE(&garbage, &element->inf);
742 ZVAL_COPY(&element->inf, inf);
744} /* }}} */
745
746/* {{{ Moves position forward */
748{
750
753 }
754
755 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
756 intern->index++;
757} /* }}} */
758
759/* {{{ Seek to position. */
761{
762 zend_long position;
764
765 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &position) == FAILURE) {
767 }
768
769 if (position < 0 || position >= zend_hash_num_elements(&intern->storage)) {
770 zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0, "Seek position " ZEND_LONG_FMT " is out of range", position);
772 }
773
774 if (position == 0) {
775 /* fast path */
777 intern->index = 0;
778 } else if (position > intern->index) {
779 /* unlike the optimization below, it's not cheap to go to the end */
780 do {
781 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
782 intern->index++;
783 } while (position > intern->index);
784 } else if (position < intern->index) {
785 /* optimization: check if it's more profitable to reset and do a forwards seek instead, it's cheap to reset */
786 if (intern->index - position > position) {
788 intern->index = 0;
789 do {
790 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
791 intern->index++;
792 } while (position > intern->index);
793 } else {
794 do {
795 zend_hash_move_backwards_ex(&intern->storage, &intern->pos);
796 intern->index--;
797 } while (position < intern->index);
798 }
799 }
800} /* }}} */
801
802/* {{{ Serializes storage */
804{
806
808 zval members, flags;
811 smart_str buf = {0};
812
815 }
816
818
819 /* storage */
820 smart_str_appendl(&buf, "x:", 2);
821 ZVAL_LONG(&flags, zend_hash_num_elements(&intern->storage));
823
825
826 while (zend_hash_has_more_elements_ex(&intern->storage, &pos) == SUCCESS) {
827 zval obj;
828 if ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &pos)) == NULL) {
829 smart_str_free(&buf);
831 RETURN_NULL();
832 }
833 ZVAL_OBJ(&obj, element->obj);
834
835 /* Protect against modification; we need a full copy because the data may be refcounted. */
836 zval inf_copy;
837 ZVAL_COPY(&inf_copy, &element->inf);
838
840 smart_str_appendc(&buf, ',');
841 php_var_serialize(&buf, &inf_copy, &var_hash);
842 smart_str_appendc(&buf, ';');
844
845 zval_ptr_dtor(&inf_copy);
846 }
847
848 /* members */
849 smart_str_appendl(&buf, "m:", 2);
850
852 php_var_serialize(&buf, &members, &var_hash); /* finishes the string */
853 zval_ptr_dtor(&members);
854
855 /* done */
857
858 RETURN_STR(smart_str_extract(&buf));
859} /* }}} */
860
861/* {{{ Unserializes storage */
863{
865
866 char *buf;
867 size_t buf_len;
868 const unsigned char *p, *s;
870 zval *pcount, *pmembers;
873
874 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
876 }
877
878 if (buf_len == 0) {
879 return;
880 }
881
882 /* storage */
883 s = p = (const unsigned char*)buf;
885
886 if (*p!= 'x' || *++p != ':') {
887 goto outexcept;
888 }
889 ++p;
890
891 pcount = var_tmp_var(&var_hash);
892 if (!php_var_unserialize(pcount, &p, s + buf_len, &var_hash) || Z_TYPE_P(pcount) != IS_LONG) {
893 goto outexcept;
894 }
895
896 --p; /* for ';' */
897 count = Z_LVAL_P(pcount);
898 if (count < 0) {
899 goto outexcept;
900 }
901
902 while (count-- > 0) {
905 zval *entry = var_tmp_var(&var_hash);
906 zval inf;
907 ZVAL_UNDEF(&inf);
908
909 if (*p != ';') {
910 goto outexcept;
911 }
912 ++p;
913 if(*p != 'O' && *p != 'C' && *p != 'r') {
914 goto outexcept;
915 }
916 /* store reference to allow cross-references between different elements */
917 if (!php_var_unserialize(entry, &p, s + buf_len, &var_hash)) {
918 goto outexcept;
919 }
920 if (*p == ',') { /* new version has inf */
921 ++p;
922 if (!php_var_unserialize(&inf, &p, s + buf_len, &var_hash)) {
923 zval_ptr_dtor(&inf);
924 goto outexcept;
925 }
926 }
927 if (Z_TYPE_P(entry) != IS_OBJECT) {
928 zval_ptr_dtor(&inf);
929 goto outexcept;
930 }
931
932 if (spl_object_storage_get_hash(&key, intern, Z_OBJ_P(entry)) == FAILURE) {
933 zval_ptr_dtor(&inf);
934 goto outexcept;
935 }
936 pelement = spl_object_storage_get(intern, &key);
937 spl_object_storage_free_hash(intern, &key);
938 if (pelement) {
939 zval obj;
940 if (!Z_ISUNDEF(pelement->inf)) {
941 var_push_dtor(&var_hash, &pelement->inf);
942 }
943 ZVAL_OBJ(&obj, pelement->obj);
944 var_push_dtor(&var_hash, &obj);
945 }
946 element = spl_object_storage_attach(intern, Z_OBJ_P(entry), Z_ISUNDEF(inf)?NULL:&inf);
947 var_replace(&var_hash, &inf, &element->inf);
948 zval_ptr_dtor(&inf);
949 }
950
951 if (*p != ';') {
952 goto outexcept;
953 }
954 ++p;
955
956 /* members */
957 if (*p!= 'm' || *++p != ':') {
958 goto outexcept;
959 }
960 ++p;
961
962 pmembers = var_tmp_var(&var_hash);
963 if (!php_var_unserialize(pmembers, &p, s + buf_len, &var_hash) || Z_TYPE_P(pmembers) != IS_ARRAY) {
964 goto outexcept;
965 }
966
967 /* copy members */
968 object_properties_load(&intern->std, Z_ARRVAL_P(pmembers));
969
971 return;
972
973outexcept:
975 zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0, "Error at offset %zd of %zd bytes", ((char*)p - buf), buf_len);
977
978} /* }}} */
979
980/* {{{ */
982{
985 zval tmp;
986
989 }
990
992
993 /* storage */
994 array_init_size(&tmp, 2 * zend_hash_num_elements(&intern->storage));
995 ZEND_HASH_FOREACH_PTR(&intern->storage, elem) {
996 zval obj;
997 ZVAL_OBJ_COPY(&obj, elem->obj);
999 Z_TRY_ADDREF(elem->inf);
1003
1004 /* members */
1006 zend_std_get_properties(&intern->std), /* always_duplicate */ 1));
1008} /* }}} */
1009
1010/* {{{ */
1012{
1014 HashTable *data;
1015 zval *storage_zv, *members_zv, *key, *val;
1016
1018 RETURN_THROWS();
1019 }
1020
1021 storage_zv = zend_hash_index_find(data, 0);
1022 members_zv = zend_hash_index_find(data, 1);
1023 if (!storage_zv || !members_zv ||
1024 Z_TYPE_P(storage_zv) != IS_ARRAY || Z_TYPE_P(members_zv) != IS_ARRAY) {
1026 "Incomplete or ill-typed serialization data", 0);
1027 RETURN_THROWS();
1028 }
1029
1030 if (zend_hash_num_elements(Z_ARRVAL_P(storage_zv)) % 2 != 0) {
1031 zend_throw_exception(spl_ce_UnexpectedValueException, "Odd number of elements", 0);
1032 RETURN_THROWS();
1033 }
1034
1035 key = NULL;
1036 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(storage_zv), val) {
1037 if (key) {
1038 if (Z_TYPE_P(key) != IS_OBJECT) {
1040 RETURN_THROWS();
1041 }
1042
1043 ZVAL_DEREF(val);
1044 spl_object_storage_attach(intern, Z_OBJ_P(key), val);
1045 key = NULL;
1046 } else {
1047 key = val;
1048 }
1050
1051 object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
1052}
1053
1054/* {{{ */
1056{
1058 RETURN_THROWS();
1059 }
1060
1061 RETURN_ARR(spl_object_storage_debug_info(Z_OBJ_P(ZEND_THIS)));
1062}
1063/* }}} */
1064
1065#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT 1
1066#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY 2
1067
1068/* {{{ Iterator that iterates over several iterators one after the other */
1070{
1071 spl_SplObjectStorage *intern;
1073
1075 RETURN_THROWS();
1076 }
1077
1078 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1079 intern->flags = flags;
1080}
1081/* }}} */
1082
1083/* {{{ Return current flags */
1085{
1087
1089 RETURN_THROWS();
1090 }
1091 RETURN_LONG(intern->flags);
1092}
1093/* }}} */
1094
1095/* {{{ Set flags */
1097{
1098 spl_SplObjectStorage *intern;
1099 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1100
1101 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &intern->flags) == FAILURE) {
1102 RETURN_THROWS();
1103 }
1104}
1105/* }}} */
1106
1107/* {{{ Attach a new iterator */
1109{
1110 spl_SplObjectStorage *intern;
1111 zend_object *iterator = NULL;
1112 zval zinfo;
1113 zend_string *info_str;
1114 zend_long info_long;
1115 bool info_is_null = 1;
1116
1120 Z_PARAM_STR_OR_LONG_OR_NULL(info_str, info_long, info_is_null)
1122
1123 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1124
1125 if (!info_is_null) {
1127
1128 if (info_str) {
1129 ZVAL_STR(&zinfo, info_str);
1130 } else {
1131 ZVAL_LONG(&zinfo, info_long);
1132 }
1133
1135 while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL) {
1136 if (fast_is_identical_function(&zinfo, &element->inf)) {
1137 zend_throw_exception(spl_ce_InvalidArgumentException, "Key duplication error", 0);
1138 RETURN_THROWS();
1139 }
1140 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1141 }
1142
1143 spl_object_storage_attach(intern, iterator, &zinfo);
1144 } else {
1145 spl_object_storage_attach(intern, iterator, NULL);
1146 }
1147}
1148/* }}} */
1149
1150/* {{{ Detaches an iterator */
1152{
1153 zval *iterator;
1155
1156 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &iterator, zend_ce_iterator) == FAILURE) {
1157 RETURN_THROWS();
1158 }
1159 spl_object_storage_detach(intern, Z_OBJ_P(iterator));
1160
1162 intern->index = 0;
1163} /* }}} */
1164
1165/* {{{ Determine whether the iterator exists */
1167{
1168 zval *iterator;
1170
1171 if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &iterator, zend_ce_iterator) == FAILURE) {
1172 RETURN_THROWS();
1173 }
1174 RETURN_BOOL(spl_object_storage_contains(intern, Z_OBJ_P(iterator)));
1175} /* }}} */
1176
1178{
1180
1182 RETURN_THROWS();
1183 }
1184
1185 RETURN_LONG(zend_hash_num_elements(&intern->storage));
1186}
1187
1188/* {{{ Rewind all attached iterator instances */
1190{
1191 spl_SplObjectStorage *intern;
1193
1194 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1195
1197 RETURN_THROWS();
1198 }
1199
1201 while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
1202 zend_object *it = element->obj;
1203 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_rewind, it, NULL);
1204 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1205 }
1206}
1207/* }}} */
1208
1209/* {{{ Move all attached iterator instances forward */
1211{
1212 spl_SplObjectStorage *intern;
1214
1215 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1216
1218 RETURN_THROWS();
1219 }
1220
1222 while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
1223 zend_object *it = element->obj;
1224 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_next, it, NULL);
1225 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1226 }
1227}
1228/* }}} */
1229
1230/* {{{ Return whether all or one sub iterator is valid depending on flags */
1232{
1233 spl_SplObjectStorage *intern;
1235 zval retval;
1236 zend_long expect, valid;
1237
1238 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1239
1241 RETURN_THROWS();
1242 }
1243
1244 if (!zend_hash_num_elements(&intern->storage)) {
1246 }
1247
1248 expect = (intern->flags & MIT_NEED_ALL) ? 1 : 0;
1249
1251 while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
1252 zend_object *it = element->obj;
1253 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_valid, it, &retval);
1254
1255 if (!Z_ISUNDEF(retval)) {
1256 valid = (Z_TYPE(retval) == IS_TRUE);
1258 } else {
1259 valid = 0;
1260 }
1261
1262 if (expect != valid) {
1263 RETURN_BOOL(!expect);
1264 }
1265
1266 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1267 }
1268
1269 RETURN_BOOL(expect);
1270}
1271/* }}} */
1272
1273static void spl_multiple_iterator_get_all(spl_SplObjectStorage *intern, int get_type, zval *return_value) /* {{{ */
1274{
1276 zval retval;
1277 int valid = 1, num_elements;
1278
1279 num_elements = zend_hash_num_elements(&intern->storage);
1280 if (num_elements < 1) {
1281 zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Called %s() on an invalid iterator",
1282 get_type == SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT ? "current" : "key");
1283 RETURN_THROWS();
1284 }
1285
1286 array_init_size(return_value, num_elements);
1287
1289 while ((element = zend_hash_get_current_data_ptr_ex(&intern->storage, &intern->pos)) != NULL && !EG(exception)) {
1290 zend_object *it = element->obj;
1291 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_valid, it, &retval);
1292
1293 if (!Z_ISUNDEF(retval)) {
1294 valid = Z_TYPE(retval) == IS_TRUE;
1296 } else {
1297 valid = 0;
1298 }
1299
1300 if (valid) {
1302 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_current, it, &retval);
1303 } else {
1304 zend_call_known_instance_method_with_0_params(it->ce->iterator_funcs_ptr->zf_key, it, &retval);
1305 }
1306 if (Z_ISUNDEF(retval)) {
1307 zend_throw_exception(spl_ce_RuntimeException, "Failed to call sub iterator method", 0);
1308 return;
1309 }
1310 } else if (intern->flags & MIT_NEED_ALL) {
1312 zend_throw_exception(spl_ce_RuntimeException, "Called current() with non valid sub iterator", 0);
1313 } else {
1314 zend_throw_exception(spl_ce_RuntimeException, "Called key() with non valid sub iterator", 0);
1315 }
1316 return;
1317 } else {
1318 ZVAL_NULL(&retval);
1319 }
1320
1321 if (intern->flags & MIT_KEYS_ASSOC) {
1322 switch (Z_TYPE(element->inf)) {
1323 case IS_LONG:
1324 add_index_zval(return_value, Z_LVAL(element->inf), &retval);
1325 break;
1326 case IS_STRING:
1327 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR(element->inf), &retval);
1328 break;
1329 default:
1331 zend_throw_exception(spl_ce_InvalidArgumentException, "Sub-Iterator is associated with NULL", 0);
1332 return;
1333 }
1334 } else {
1335 add_next_index_zval(return_value, &retval);
1336 }
1337
1338 zend_hash_move_forward_ex(&intern->storage, &intern->pos);
1339 }
1340}
1341/* }}} */
1342
1343/* {{{ Return an array of all registered Iterator instances current() result */
1345{
1346 spl_SplObjectStorage *intern;
1347 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1348
1350 RETURN_THROWS();
1351 }
1352
1353 spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT, return_value);
1354}
1355/* }}} */
1356
1357/* {{{ Return an array of all registered Iterator instances key() result */
1359{
1360 spl_SplObjectStorage *intern;
1361 intern = Z_SPLOBJSTORAGE_P(ZEND_THIS);
1362
1364 RETURN_THROWS();
1365 }
1366
1367 spl_multiple_iterator_get_all(intern, SPL_MULTIPLE_ITERATOR_GET_ALL_KEY, return_value);
1368}
1369/* }}} */
1370
1371/* {{{ PHP_MINIT_FUNCTION(spl_observer) */
1373{
1374 spl_ce_SplObserver = register_class_SplObserver();
1375 spl_ce_SplSubject = register_class_SplSubject();
1376
1378 spl_ce_SplObjectStorage->create_object = spl_SplObjectStorage_new;
1379 spl_ce_SplObjectStorage->default_object_handlers = &spl_handler_SplObjectStorage;
1380
1381 memcpy(&spl_handler_SplObjectStorage, &std_object_handlers, sizeof(zend_object_handlers));
1382
1383 spl_handler_SplObjectStorage.offset = XtOffsetOf(spl_SplObjectStorage, std);
1384 spl_handler_SplObjectStorage.compare = spl_object_storage_compare_objects;
1385 spl_handler_SplObjectStorage.clone_obj = spl_object_storage_clone;
1386 spl_handler_SplObjectStorage.get_gc = spl_object_storage_get_gc;
1387 spl_handler_SplObjectStorage.free_obj = spl_SplObjectStorage_free_storage;
1388 spl_handler_SplObjectStorage.read_dimension = spl_object_storage_read_dimension;
1389 spl_handler_SplObjectStorage.write_dimension = spl_object_storage_write_dimension;
1390 spl_handler_SplObjectStorage.has_dimension = spl_object_storage_has_dimension;
1391 spl_handler_SplObjectStorage.unset_dimension = spl_object_storage_unset_dimension;
1392
1393 spl_ce_MultipleIterator = register_class_MultipleIterator(zend_ce_iterator);
1394 spl_ce_MultipleIterator->create_object = spl_SplObjectStorage_new;
1395 spl_ce_MultipleIterator->default_object_handlers = &spl_handler_SplObjectStorage;
1396
1397 return SUCCESS;
1398}
1399/* }}} */
file_private int get_type(const struct type_tbl_s *tbl, const char *l, const char **t)
Definition apprentice.c:317
bool exception
Definition assert.c:30
rewind($stream)
count(Countable|array $value, int $mode=COUNT_NORMAL)
char s[4]
Definition cdf.c:77
zend_ffi_type * type
Definition ffi.c:3812
DL_HANDLE handle
Definition ffi.c:3028
zend_long n
Definition ffi.c:4979
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
zval * val
Definition ffi.c:4262
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
zend_long offset
char * mode
#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
#define PHP_COUNT_NORMAL
Definition php_array.h:59
#define PHP_COUNT_RECURSIVE
Definition php_array.h:60
unsigned const char * pos
Definition php_ffi.h:52
unsigned char key[REFLECTION_KEY_LEN]
PHPAPI zend_string * php_spl_object_hash(zend_object *obj)
Definition php_spl.c:670
#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 void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval *nzval)
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)
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval *val)
#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
PHPAPI zend_class_entry * spl_ce_RuntimeException
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_SeekableIterator
#define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zstr_method)
PHPAPI zend_class_entry * spl_ce_SplSubject
#define SOS_OVERRIDDEN_UNSET_DIMENSION
#define SPL_MULTIPLE_ITERATOR_GET_ALL_KEY
struct _spl_SplObjectStorageElement spl_SplObjectStorageElement
PHPAPI zend_class_entry * spl_ce_SplObjectStorage
#define SOS_OVERRIDDEN_WRITE_DIMENSION
#define SPL_MULTIPLE_ITERATOR_GET_ALL_CURRENT
#define Z_SPLOBJSTORAGE_P(zv)
PHPAPI zend_class_entry * spl_ce_MultipleIterator
PHPAPI zend_class_entry * spl_ce_SplObserver
#define SOS_OVERRIDDEN_READ_DIMENSION
struct _spl_SplObjectStorage spl_SplObjectStorage
@ MIT_KEYS_ASSOC
@ MIT_KEYS_NUMERIC
@ MIT_NEED_ALL
PHPAPI zend_long php_count_recursive(HashTable *ht)
Definition array.c:609
zend_function * fptr_get_hash
zend_class_iterator_funcs * iterator_funcs_ptr
Definition zend.h:189
zend_string * name
Definition zend.h:149
HashTable function_table
Definition zend.h:163
zend_object_get_properties_t get_properties
zend_class_entry * ce
Definition zend_types.h:560
const zend_object_handlers * handlers
Definition zend_types.h:561
uint32_t handle
Definition zend_types.h:558
zend_class_entry * scope
struct _zend_function::@236135173067030250234125302313220025134003177336 common
ZEND_API ZEND_COLD void zend_type_error(const char *format,...)
Definition zend.c:1824
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value)
Definition zend_API.c:2027
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
#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 array_init_size(arg, size)
Definition zend_API.h:538
#define RETURN_ARR(r)
Definition zend_API.h:1050
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define zend_parse_parameters_none()
Definition zend_API.h:353
#define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null)
Definition zend_API.h:2168
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
#define RETURN_NEW_STR(s)
Definition zend_API.h:1041
#define RETURN_THROWS()
Definition zend_API.h:1060
#define Z_PARAM_OBJ(dest)
Definition zend_API.h:1955
#define Z_PARAM_OBJ_OF_CLASS(dest, _ce)
Definition zend_API.h:1997
#define RETURN_STR(s)
Definition zend_API.h:1039
#define ZEND_THIS
Definition zend_API.h:523
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define array_init(arg)
Definition zend_API.h:537
#define efree(ptr)
Definition zend_alloc.h:155
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
zend_string_release_ex(func->internal_function.function_name, 0)
#define BP_VAR_IS
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,...)
union _zend_function zend_function
ZEND_API zend_get_gc_buffer * zend_get_gc_buffer_create(void)
Definition zend_gc.c:2130
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
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 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_index_lookup(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1234
ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, bool ordered)
Definition zend_hash.c:3197
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1692
ZEND_API zend_result ZEND_FASTCALL zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos)
Definition zend_hash.c:2812
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 zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
Definition zend_hash.c:1534
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
struct _zend_hash_key zend_hash_key
#define ZEND_HASH_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1118
#define zend_new_array(size)
Definition zend_hash.h:338
#define zend_hash_get_current_data_ptr(ht)
Definition zend_hash.h:990
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_VAL(ht, _val)
Definition zend_hash.h:1102
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
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check_empty)
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset)
ZEND_API zval * zend_std_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
ZEND_API void zend_std_write_dimension(zend_object *object, zval *offset, zval *value)
#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 int ZEND_FASTCALL zend_compare(zval *op1, zval *op2)
#define ZEND_UNCOMPARABLE
#define EXPECTED(condition)
#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
int(* compare_func_t)(const void *, const void *)
Definition zend_types.h:104
#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 ZVAL_UNDEF(z)
#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 IS_PTR
Definition zend_types.h:624
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define ZVAL_COPY_DEREF(z, v)
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_PTR_P(zval_p)
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_ADDREF(p)
Definition zend_types.h:709
#define IS_NULL
Definition zend_types.h:601
#define Z_OBJ_HANDLE_P(zval_p)
Definition zend_types.h:999
#define ZVAL_OBJ(z, o)
@ FAILURE
Definition zend_types.h:61
#define Z_TRY_ADDREF(z)
#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 ZVAL_COPY(z, v)
uint32_t HashPosition
Definition zend_types.h:548
#define ZVAL_PTR(z, p)
#define ZVAL_OBJ_COPY(z, o)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define Z_ARRVAL(zval)
Definition zend_types.h:986
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
ZEND_API void zval_add_ref(zval *p)
zval retval
zval * return_value
zend_refcounted * garbage
zval * ret