php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_object_handlers.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19*/
20
21#include "zend.h"
22#include "zend_globals.h"
23#include "zend_lazy_objects.h"
24#include "zend_variables.h"
25#include "zend_API.h"
26#include "zend_objects.h"
27#include "zend_objects_API.h"
29#include "zend_interfaces.h"
30#include "zend_exceptions.h"
31#include "zend_closures.h"
32#include "zend_compile.h"
33#include "zend_hash.h"
34#include "zend_property_hooks.h"
35#include "zend_observer.h"
36
37#define DEBUG_OBJECT_HANDLERS 0
38
39#define ZEND_WRONG_PROPERTY_OFFSET 0
40#define ZEND_HOOKED_PROPERTY_OFFSET 1
41
42/* guard flags */
43#define IN_GET ZEND_GUARD_PROPERTY_GET
44#define IN_SET ZEND_GUARD_PROPERTY_SET
45#define IN_UNSET ZEND_GUARD_PROPERTY_UNSET
46#define IN_ISSET ZEND_GUARD_PROPERTY_ISSET
47#define IN_HOOK ZEND_GUARD_PROPERTY_HOOK
48
49static zend_always_inline bool zend_objects_check_stack_limit(void)
50{
51#ifdef ZEND_CHECK_STACK_LIMIT
52 return zend_call_stack_overflowed(EG(stack_limit));
53#else
54 return false;
55#endif
56}
57
58/*
59 __X accessors explanation:
60
61 if we have __get and property that is not part of the properties array is
62 requested, we call __get handler. If it fails, we return uninitialized.
63
64 if we have __set and property that is not part of the properties array is
65 set, we call __set handler. If it fails, we do not change the array.
66
67 for both handlers above, when we are inside __get/__set, no further calls for
68 __get/__set for this property of this object will be made, to prevent endless
69 recursion and enable accessors to change properties array.
70
71 if we have __call and method which is not part of the class function table is
72 called, we cal __call handler.
73*/
74
76{
77 if (!zobj->properties) {
79 zend_class_entry *ce = zobj->ce;
80 int i;
81
85 for (i = 0; i < ce->default_properties_count; i++) {
87
88 if (!prop_info) {
89 continue;
90 }
91
94 }
95
96 _zend_hash_append_ind(zobj->properties, prop_info->name,
97 OBJ_PROP(zobj, prop_info->offset));
98 }
99 }
100 }
101
102 return zobj->properties;
103}
104/* }}} */
105
106/* Implements the fast path for array cast */
108{
110 zend_class_entry *ce = zobj->ce;
111 HashTable *ht;
112 zval* prop;
113 int i;
114
115 ZEND_ASSERT(!(zend_object_is_lazy_proxy(zobj) && zend_lazy_object_initialized(zobj)));
116 ZEND_ASSERT(!zobj->properties);
118 if (ce->default_properties_count) {
120 for (i = 0; i < ce->default_properties_count; i++) {
122
123 if (!prop_info) {
124 continue;
125 }
126
127 prop = OBJ_PROP(zobj, prop_info->offset);
128 if (UNEXPECTED(Z_TYPE_P(prop) == IS_UNDEF)) {
129 continue;
130 }
131
132 if (Z_ISREF_P(prop) && Z_REFCOUNT_P(prop) == 1) {
133 prop = Z_REFVAL_P(prop);
134 }
135
136 Z_TRY_ADDREF_P(prop);
137 _zend_hash_append(ht, prop_info->name, prop);
138 }
139 }
140 return ht;
141}
142/* }}} */
143
145{
146 return zend_std_get_properties_ex(zobj);
147}
148/* }}} */
149
150/* Fetch properties HashTable without triggering lazy initialization */
152{
153 if (zobj->handlers->get_properties == zend_std_get_properties) {
154 if (UNEXPECTED(zend_object_is_lazy_proxy(zobj)
155 && zend_lazy_object_initialized(zobj))) {
157 return zend_get_properties_no_lazy_init(instance);
158 }
159
160 if (!zobj->properties) {
162 }
163 return zobj->properties;
164 }
165
166 ZEND_ASSERT(!zend_object_is_lazy(zobj));
167
168 return zobj->handlers->get_properties(zobj);
169}
170
172{
173 if (zobj->handlers->get_properties != zend_std_get_properties) {
174 *table = NULL;
175 *n = 0;
176 return zobj->handlers->get_properties(zobj);
177 } else {
178 if (UNEXPECTED(zend_object_is_lazy(zobj))) {
179 return zend_lazy_object_get_gc(zobj, table, n);
180 } else if (zobj->properties) {
181 *table = NULL;
182 *n = 0;
183 return zobj->properties;
184 } else {
185 *table = zobj->properties_table;
186 *n = zobj->ce->default_properties_count;
187 return NULL;
188 }
189 }
190}
191/* }}} */
192
193ZEND_API HashTable *zend_std_get_debug_info(zend_object *object, int *is_temp) /* {{{ */
194{
195 zend_class_entry *ce = object->ce;
196 zval retval;
197 HashTable *ht;
198
199 if (!ce->__debugInfo) {
200 if (UNEXPECTED(zend_object_is_lazy(object))) {
201 return zend_lazy_object_debug_info(object, is_temp);
202 }
203
204 *is_temp = 0;
205 return object->handlers->get_properties(object);
206 }
207
208 zend_call_known_instance_method_with_0_params(ce->__debugInfo, object, &retval);
209 if (Z_TYPE(retval) == IS_ARRAY) {
210 if (!Z_REFCOUNTED(retval)) {
211 *is_temp = 1;
213 } else if (Z_REFCOUNT(retval) <= 1) {
214 *is_temp = 1;
215 ht = Z_ARR(retval);
216 return ht;
217 } else {
218 *is_temp = 0;
220 return Z_ARRVAL(retval);
221 }
222 } else if (Z_TYPE(retval) == IS_NULL) {
223 *is_temp = 1;
224 ht = zend_new_array(0);
225 return ht;
226 }
227
228 zend_error_noreturn(E_ERROR, ZEND_DEBUGINFO_FUNC_NAME "() must return an array");
229
230 return NULL; /* Compilers are dumb and don't understand that noreturn means that the function does NOT need a return value... */
231}
232/* }}} */
233
234static void zend_std_call_getter(zend_object *zobj, zend_string *prop_name, zval *retval) /* {{{ */
235{
236 zval member;
237 ZVAL_STR(&member, prop_name);
238 zend_call_known_instance_method_with_1_params(zobj->ce->__get, zobj, retval, &member);
239}
240/* }}} */
241
242static void zend_std_call_setter(zend_object *zobj, zend_string *prop_name, zval *value) /* {{{ */
243{
244 zval args[2];
245 ZVAL_STR(&args[0], prop_name);
247 zend_call_known_instance_method(zobj->ce->__set, zobj, NULL, 2, args);
248}
249/* }}} */
250
251static void zend_std_call_unsetter(zend_object *zobj, zend_string *prop_name) /* {{{ */
252{
253 zval member;
254 ZVAL_STR(&member, prop_name);
255 zend_call_known_instance_method_with_1_params(zobj->ce->__unset, zobj, NULL, &member);
256}
257/* }}} */
258
259static void zend_std_call_issetter(zend_object *zobj, zend_string *prop_name, zval *retval) /* {{{ */
260{
261 zval member;
262 ZVAL_STR(&member, prop_name);
263 zend_call_known_instance_method_with_1_params(zobj->ce->__isset, zobj, retval, &member);
264}
265/* }}} */
266
267
268static zend_always_inline bool is_derived_class(const zend_class_entry *child_class, const zend_class_entry *parent_class) /* {{{ */
269{
270 child_class = child_class->parent;
271 while (child_class) {
272 if (child_class == parent_class) {
273 return 1;
274 }
275 child_class = child_class->parent;
276 }
277
278 return 0;
279}
280/* }}} */
281
282static zend_never_inline int is_protected_compatible_scope(const zend_class_entry *ce, const zend_class_entry *scope) /* {{{ */
283{
284 return scope &&
285 (is_derived_class(ce, scope) || is_derived_class(scope, ce));
286}
287/* }}} */
288
289static zend_never_inline zend_property_info *zend_get_parent_private_property(zend_class_entry *scope, const zend_class_entry *ce, zend_string *member) /* {{{ */
290{
291 zval *zv;
293
294 if (scope != ce && scope && is_derived_class(ce, scope)) {
295 zv = zend_hash_find(&scope->properties_info, member);
296 if (zv != NULL) {
298 if ((prop_info->flags & ZEND_ACC_PRIVATE)
299 && prop_info->ce == scope) {
300 return prop_info;
301 }
302 }
303 }
304 return NULL;
305}
306/* }}} */
307
308static ZEND_COLD zend_never_inline void zend_bad_property_access(const zend_property_info *property_info, const zend_class_entry *ce, const zend_string *member) /* {{{ */
309{
310 zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ZSTR_VAL(ce->name), ZSTR_VAL(member));
311}
312/* }}} */
313
314static ZEND_COLD zend_never_inline void zend_bad_property_name(void) /* {{{ */
315{
316 zend_throw_error(NULL, "Cannot access property starting with \"\\0\"");
317}
318/* }}} */
319
320static ZEND_COLD zend_never_inline void zend_forbidden_dynamic_property(
321 const zend_class_entry *ce, const zend_string *member) {
322 zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
323 ZSTR_VAL(ce->name), ZSTR_VAL(member));
324}
325
326static ZEND_COLD zend_never_inline bool zend_deprecated_dynamic_property(
327 zend_object *obj, const zend_string *member) {
328 GC_ADDREF(obj);
329 zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
330 ZSTR_VAL(obj->ce->name), ZSTR_VAL(member));
331 if (UNEXPECTED(GC_DELREF(obj) == 0)) {
332 zend_class_entry *ce = obj->ce;
334 if (!EG(exception)) {
335 /* We cannot continue execution and have to throw an exception */
336 zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
337 ZSTR_VAL(ce->name), ZSTR_VAL(member));
338 }
339 return 0;
340 }
341 return 1;
342}
343
344static ZEND_COLD zend_never_inline void zend_readonly_property_unset_error(
345 zend_class_entry *ce, zend_string *member) {
346 zend_throw_error(NULL, "Cannot unset readonly property %s::$%s",
347 ZSTR_VAL(ce->name), ZSTR_VAL(member));
348}
349
350static zend_always_inline zend_class_entry *get_fake_or_executed_scope(void)
351{
352 if (UNEXPECTED(EG(fake_scope))) {
353 return EG(fake_scope);
354 } else {
356 }
357}
358
359static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot, const zend_property_info **info_ptr) /* {{{ */
360{
361 zval *zv;
362 zend_property_info *property_info;
363 uint32_t flags;
364 uintptr_t offset;
365
366 if (cache_slot && EXPECTED(ce == CACHED_PTR_EX(cache_slot))) {
367 *info_ptr = CACHED_PTR_EX(cache_slot + 2);
368 return (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
369 }
370
371 if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)
372 || UNEXPECTED((zv = zend_hash_find(&ce->properties_info, member)) == NULL)) {
373 if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0') && ZSTR_LEN(member) != 0) {
374 if (!silent) {
375 zend_bad_property_name();
376 }
378 }
379dynamic:
380 if (cache_slot) {
382 CACHE_PTR_EX(cache_slot + 2, NULL);
383 }
385 }
386
387 property_info = (zend_property_info*)Z_PTR_P(zv);
388 flags = property_info->flags;
389
391 zend_class_entry *scope = get_fake_or_executed_scope();
392
393 if (property_info->ce != scope) {
394 if (flags & ZEND_ACC_CHANGED) {
395 zend_property_info *p = zend_get_parent_private_property(scope, ce, member);
396
397 /* If there is a public/protected instance property on ce, don't try to use a
398 * private static property on scope. If both are static, prefer the static
399 * property on scope. This will throw a static property notice, rather than
400 * a visibility error. */
401 if (p && (!(p->flags & ZEND_ACC_STATIC) || (flags & ZEND_ACC_STATIC))) {
402 property_info = p;
403 flags = property_info->flags;
404 goto found;
405 } else if (flags & ZEND_ACC_PUBLIC) {
406 goto found;
407 }
408 }
409 if (flags & ZEND_ACC_PRIVATE) {
410 if (property_info->ce != ce) {
411 goto dynamic;
412 } else {
413wrong:
414 /* Information was available, but we were denied access. Error out. */
415 if (!silent) {
416 zend_bad_property_access(property_info, ce, member);
417 }
419 }
420 } else {
422 if (UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
423 goto wrong;
424 }
425 }
426 }
427 }
428
429found:
431 if (!silent) {
432 zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member));
433 }
435 }
436
437 if (property_info->hooks) {
438 *info_ptr = property_info;
439 if (cache_slot) {
441 CACHE_PTR_EX(cache_slot + 2, property_info);
442 }
444 }
445
446 offset = property_info->offset;
447 if (EXPECTED(!ZEND_TYPE_IS_SET(property_info->type))) {
448 property_info = NULL;
449 } else {
450 *info_ptr = property_info;
451 }
452 if (cache_slot) {
453 CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(uintptr_t)offset);
454 CACHE_PTR_EX(cache_slot + 2, property_info);
455 }
456 return offset;
457}
458/* }}} */
459
460static ZEND_COLD void zend_wrong_offset(zend_class_entry *ce, zend_string *member) /* {{{ */
461{
462 const zend_property_info *dummy;
463
464 /* Trigger the correct error */
465 zend_get_property_offset(ce, member, 0, NULL, &dummy);
466}
467/* }}} */
468
470{
471 zval *zv;
472 zend_property_info *property_info;
473 uint32_t flags;
474
475 if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)
476 || EXPECTED((zv = zend_hash_find(&ce->properties_info, member)) == NULL)) {
477 if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0') && ZSTR_LEN(member) != 0) {
478 if (!silent) {
479 zend_bad_property_name();
480 }
482 }
483dynamic:
484 return NULL;
485 }
486
487 property_info = (zend_property_info*)Z_PTR_P(zv);
488 flags = property_info->flags;
489
491 zend_class_entry *scope = get_fake_or_executed_scope();
492 if (property_info->ce != scope) {
493 if (flags & ZEND_ACC_CHANGED) {
494 zend_property_info *p = zend_get_parent_private_property(scope, ce, member);
495
496 if (p) {
497 property_info = p;
498 flags = property_info->flags;
499 goto found;
500 } else if (flags & ZEND_ACC_PUBLIC) {
501 goto found;
502 }
503 }
504 if (flags & ZEND_ACC_PRIVATE) {
505 if (property_info->ce != ce) {
506 goto dynamic;
507 } else {
508wrong:
509 /* Information was available, but we were denied access. Error out. */
510 if (!silent) {
511 zend_bad_property_access(property_info, ce, member);
512 }
514 }
515 } else {
517 if (UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
518 goto wrong;
519 }
520 }
521 }
522 }
523
524found:
526 if (!silent) {
527 zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member));
528 }
529 }
530 return property_info;
531}
532/* }}} */
533
534ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic) /* {{{ */
535{
536 zend_property_info *property_info;
537 const char *class_name = NULL;
538 const char *prop_name;
539 zend_string *member;
540 size_t prop_name_len;
541
542 if (ZSTR_VAL(prop_info_name)[0] == 0) {
543 if (is_dynamic) {
544 return SUCCESS;
545 }
546
547 zend_unmangle_property_name_ex(prop_info_name, &class_name, &prop_name, &prop_name_len);
548 member = zend_string_init(prop_name, prop_name_len, 0);
549 property_info = zend_get_property_info(zobj->ce, member, 1);
550 zend_string_release_ex(member, 0);
551 if (property_info == NULL || property_info == ZEND_WRONG_PROPERTY_INFO) {
552 return FAILURE;
553 }
554
555 if (class_name[0] != '*') {
556 if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
557 /* we we're looking for a private prop but found a non private one of the same name */
558 return FAILURE;
559 } else if (strcmp(ZSTR_VAL(prop_info_name)+1, ZSTR_VAL(property_info->name)+1)) {
560 /* we we're looking for a private prop but found a private one of the same name but another class */
561 return FAILURE;
562 }
563 } else {
564 ZEND_ASSERT(property_info->flags & ZEND_ACC_PROTECTED);
565 }
566 return SUCCESS;
567 } else {
568 property_info = zend_get_property_info(zobj->ce, prop_info_name, 1);
569 if (property_info == NULL) {
570 ZEND_ASSERT(is_dynamic);
571 return SUCCESS;
572 } else if (property_info == ZEND_WRONG_PROPERTY_INFO) {
573 return FAILURE;
574 }
575 return (property_info->flags & ZEND_ACC_PUBLIC) ? SUCCESS : FAILURE;
576 }
577}
578/* }}} */
579
583 zend_class_entry *scope = get_fake_or_executed_scope();
584 if (prop_info->ce == scope) {
585 return true;
586 }
588 && is_protected_compatible_scope(prop_info->ce, scope));
589}
590
591static void zend_property_guard_dtor(zval *el) /* {{{ */ {
592 uint32_t *ptr = (uint32_t*)Z_PTR_P(el);
593 if (EXPECTED(!(((uintptr_t)ptr) & 1))) {
594 efree_size(ptr, sizeof(uint32_t));
595 }
596}
597/* }}} */
598
599static zend_always_inline zval *zend_get_guard_value(zend_object *zobj)
600{
601 return zobj->properties_table + zobj->ce->default_properties_count;
602}
603
605{
606 HashTable *guards;
607 zval *zv;
608 uint32_t *ptr;
609
610
611 ZEND_ASSERT(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS);
612 zv = zend_get_guard_value(zobj);
613 if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
614 zend_string *str = Z_STR_P(zv);
615 if (EXPECTED(str == member) ||
616 /* str and member don't necessarily have a pre-calculated hash value here */
617 EXPECTED(zend_string_equal_content(str, member))) {
618 return &Z_GUARD_P(zv);
619 } else if (EXPECTED(Z_GUARD_P(zv) == 0)) {
620 zval_ptr_dtor_str(zv);
621 ZVAL_STR_COPY(zv, member);
622 return &Z_GUARD_P(zv);
623 } else {
624 ALLOC_HASHTABLE(guards);
625 zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
626 /* mark pointer as "special" using low bit */
627 zend_hash_add_new_ptr(guards, str,
628 (void*)(((uintptr_t)&Z_GUARD_P(zv)) | 1));
629 zval_ptr_dtor_str(zv);
630 ZVAL_ARR(zv, guards);
631 }
632 } else if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) {
633 guards = Z_ARRVAL_P(zv);
634 ZEND_ASSERT(guards != NULL);
635 zv = zend_hash_find(guards, member);
636 if (zv != NULL) {
637 return (uint32_t*)(((uintptr_t)Z_PTR_P(zv)) & ~1);
638 }
639 } else {
641 ZVAL_STR_COPY(zv, member);
643 return &Z_GUARD_P(zv);
644 }
645 /* we have to allocate uint32_t separately because ht->arData may be reallocated */
646 ptr = (uint32_t*)emalloc(sizeof(uint32_t));
647 *ptr = 0;
648 return (uint32_t*)zend_hash_add_new_ptr(guards, member, ptr);
649}
650/* }}} */
651
653{
654 if (!(zobj->ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
655 return NULL;
656 }
657 zval *zv = zend_get_guard_value(zobj);
658 return &Z_GUARD_P(zv);
659}
660
661ZEND_COLD static void zend_typed_property_uninitialized_access(const zend_property_info *prop_info, zend_string *name)
662{
663 zend_throw_error(NULL, "Typed property %s::$%s must not be accessed before initialization",
664 ZSTR_VAL(prop_info->ce->name),
665 ZSTR_VAL(name));
666}
667
668static ZEND_FUNCTION(zend_parent_hook_get_trampoline);
669static ZEND_FUNCTION(zend_parent_hook_set_trampoline);
670
671static bool zend_is_in_hook(const zend_property_info *prop_info)
672{
673 zend_execute_data *execute_data = EG(current_execute_data);
674 if (!execute_data || !EX(func) || !EX(func)->common.prop_info) {
675 return false;
676 }
677
678 const zend_property_info *parent_info = EX(func)->common.prop_info;
679 ZEND_ASSERT(prop_info->prototype && parent_info->prototype);
680 return prop_info->prototype == parent_info->prototype;
681}
682
683static bool zend_should_call_hook(const zend_property_info *prop_info, const zend_object *obj)
684{
685 if (!zend_is_in_hook(prop_info)) {
686 return true;
687 }
688
689 /* execute_data and This are guaranteed to be set if zend_is_in_hook() returns true. */
690 zend_object *parent_obj = Z_OBJ(EG(current_execute_data)->This);
691 if (parent_obj == obj) {
692 return false;
693 }
694
695 if (zend_object_is_lazy_proxy(parent_obj)
696 && zend_lazy_object_initialized(parent_obj)
697 && zend_lazy_object_get_instance(parent_obj) == obj) {
698 return false;
699 }
700
701 return true;
702}
703
704static ZEND_COLD void zend_throw_no_prop_backing_value_access(zend_string *class_name, zend_string *prop_name, bool is_read)
705{
706 zend_throw_error(NULL, "Must not %s virtual property %s::$%s",
707 is_read ? "read from" : "write to",
708 ZSTR_VAL(class_name), ZSTR_VAL(prop_name));
709}
710
711static bool zend_call_get_hook(
712 const zend_property_info *prop_info, zend_string *prop_name,
714{
715 if (!zend_should_call_hook(prop_info, zobj)) {
716 if (UNEXPECTED(prop_info->flags & ZEND_ACC_VIRTUAL)) {
717 zend_throw_no_prop_backing_value_access(zobj->ce->name, prop_name, /* is_read */ true);
718 }
719 return false;
720 }
721
722 zend_call_known_instance_method_with_0_params(get, zobj, rv);
723
724 return true;
725}
726
728{
729 zval *retval;
730 uintptr_t property_offset;
732 uint32_t *guard = NULL;
733
734#if DEBUG_OBJECT_HANDLERS
735 fprintf(stderr, "Read object #%d property: %s\n", zobj->handle, ZSTR_VAL(name));
736#endif
737
738 /* make zend_get_property_info silent if we have getter - we may want to use it */
739 property_offset = zend_get_property_offset(zobj->ce, name, (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot, &prop_info);
740
741 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
742try_again:
743 retval = OBJ_PROP(zobj, property_offset);
744
746 && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)
748 if (Z_TYPE_P(retval) == IS_OBJECT) {
749 /* For objects, W/RW/UNSET fetch modes might not actually modify object.
750 * Similar as with magic __get() allow them, but return the value as a copy
751 * to make sure no actual modification is possible. */
753 retval = rv;
754 goto exit;
755 } else if (Z_TYPE_P(retval) == IS_UNDEF && type == BP_VAR_UNSET) {
756 retval = &EG(uninitialized_zval);
757 goto exit;
758 }
759 if (prop_info->flags & ZEND_ACC_READONLY) {
761 } else {
763 }
764 retval = &EG(uninitialized_zval);
765 goto exit;
766 }
767 if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
768 goto exit;
769 }
771 /* Skip __get() for uninitialized typed properties */
772 goto uninit_error;
773 }
774 } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
775 if (EXPECTED(zobj->properties != NULL)) {
776 if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
777 uintptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);
778
779 if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
780 Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
781
782 if (EXPECTED(p->key == name) ||
783 (EXPECTED(p->h == ZSTR_H(name)) &&
784 EXPECTED(p->key != NULL) &&
785 EXPECTED(zend_string_equal_content(p->key, name)))) {
786 retval = &p->val;
787 goto exit;
788 }
789 }
790 CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
791 }
792 retval = zend_hash_find(zobj->properties, name);
793 if (EXPECTED(retval)) {
794 if (cache_slot) {
795 uintptr_t idx = (char*)retval - (char*)zobj->properties->arData;
796 CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
797 }
798 goto exit;
799 }
800 }
801 } else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
803 if (!get) {
804 if (prop_info->flags & ZEND_ACC_VIRTUAL) {
805 zend_throw_error(NULL, "Property %s::$%s is write-only",
806 ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
807 return &EG(uninitialized_zval);
808 }
809 /* Cache the fact that this hook has trivial read. This only applies to
810 * BP_VAR_R and BP_VAR_IS fetches. */
812
813 retval = OBJ_PROP(zobj, prop_info->offset);
815 /* As hooked properties can't be unset, the only way to end up with an undef
816 * value is via an uninitialized property. */
818 goto uninit_error;
819 }
820
821 if (UNEXPECTED(type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
823 zend_throw_error(NULL, "Indirect modification of %s::$%s is not allowed",
824 ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
825 goto exit;
826 }
828 retval = rv;
829 }
830 goto exit;
831 }
832
833 zend_class_entry *ce = zobj->ce;
834
835 if (!zend_call_get_hook(prop_info, name, get, zobj, rv)) {
836 if (EG(exception)) {
837 return &EG(uninitialized_zval);
838 }
839
840 /* Reads from backing store can only occur in hooks, and hence will always remain simple. */
841 zend_execute_data *execute_data = EG(current_execute_data);
842 if (cache_slot && EX(opline) && EX(opline)->opcode == ZEND_FETCH_OBJ_R && EX(opline)->op1_type == IS_UNUSED) {
844 }
845
846 property_offset = prop_info->offset;
847 if (!ZEND_TYPE_IS_SET(prop_info->type)) {
848 prop_info = NULL;
849 }
850 goto try_again;
851 }
852
853 if (EXPECTED(cache_slot
856 && !ce->create_object
857 && !zend_is_in_hook(prop_info)
858 && !(prop_info->hooks[ZEND_PROPERTY_HOOK_GET]->common.fn_flags & ZEND_ACC_RETURN_REFERENCE))) {
860 }
861
862 if (Z_TYPE_P(rv) != IS_UNDEF) {
863 retval = rv;
864 if (!Z_ISREF_P(rv)
865 && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)
867 zend_throw_error(NULL, "Indirect modification of %s::$%s is not allowed",
868 ZSTR_VAL(ce->name), ZSTR_VAL(name));
869 }
870 } else {
871 retval = &EG(uninitialized_zval);
872 }
873
874 goto exit;
875 } else if (UNEXPECTED(EG(exception))) {
876 retval = &EG(uninitialized_zval);
877 goto exit;
878 }
879
880 retval = &EG(uninitialized_zval);
881
882 /* magic isset */
883 if ((type == BP_VAR_IS) && zobj->ce->__isset) {
884 zval tmp_result;
886
887 if (!((*guard) & IN_ISSET)) {
889 ZVAL_UNDEF(&tmp_result);
890
891 *guard |= IN_ISSET;
892 zend_std_call_issetter(zobj, name, &tmp_result);
893 *guard &= ~IN_ISSET;
894
895 if (!zend_is_true(&tmp_result)) {
896 retval = &EG(uninitialized_zval);
898 zval_ptr_dtor(&tmp_result);
899 goto exit;
900 }
901
902 zval_ptr_dtor(&tmp_result);
903 if (zobj->ce->__get && !((*guard) & IN_GET)) {
904 goto call_getter;
905 }
907 } else if (zobj->ce->__get && !((*guard) & IN_GET)) {
908 goto call_getter_addref;
909 }
910 } else if (zobj->ce->__get) {
911 /* magic get */
913 if (!((*guard) & IN_GET)) {
914 /* have getter - try with it! */
915call_getter_addref:
917call_getter:
918 *guard |= IN_GET; /* prevent circular getting */
919 zend_std_call_getter(zobj, name, rv);
920 *guard &= ~IN_GET;
921
922 if (Z_TYPE_P(rv) != IS_UNDEF) {
923 retval = rv;
924 if (!Z_ISREF_P(rv) &&
925 (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
926 if (UNEXPECTED(Z_TYPE_P(rv) != IS_OBJECT)) {
927 zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
928 }
929 }
930 } else {
931 retval = &EG(uninitialized_zval);
932 }
933
934 if (prop_info) {
936 }
937
939 goto exit;
940 } else if (UNEXPECTED(IS_WRONG_PROPERTY_OFFSET(property_offset))) {
941 /* Trigger the correct error */
942 zend_wrong_offset(zobj->ce, name);
944 retval = &EG(uninitialized_zval);
945 goto exit;
946 }
947 }
948
949uninit_error:
950 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
953 if (!zobj) {
954 retval = &EG(uninitialized_zval);
955 goto exit;
956 }
957
958 if (UNEXPECTED(guard)) {
959 uint32_t guard_type = (type == BP_VAR_IS) && zobj->ce->__isset
960 ? IN_ISSET : IN_GET;
962 if (!((*guard) & guard_type)) {
963 (*guard) |= guard_type;
964 retval = zend_std_read_property(zobj, name, type, cache_slot, rv);
965 (*guard) &= ~guard_type;
966 return retval;
967 }
968 }
969
970 return zend_std_read_property(zobj, name, type, cache_slot, rv);
971 }
972 }
973 if (type != BP_VAR_IS) {
974 if (prop_info) {
975 zend_typed_property_uninitialized_access(prop_info, name);
976 } else {
977 zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
978 }
979 }
980 retval = &EG(uninitialized_zval);
981
982exit:
983 return retval;
984}
985/* }}} */
986
987static zend_always_inline bool property_uses_strict_types(void) {
988 zend_execute_data *execute_data = EG(current_execute_data);
989 return execute_data
990 && execute_data->func
991 && ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data));
992}
993
994static zval *forward_write_to_lazy_object(zend_object *zobj,
995 zend_string *name, zval *value, void **cache_slot, bool guarded)
996{
998
999 /* backup value as it may change during initialization */
1000 zval backup;
1001 ZVAL_COPY(&backup, value);
1002
1004 if (UNEXPECTED(!instance)) {
1005 zval_ptr_dtor(&backup);
1006 return &EG(error_zval);
1007 }
1008
1009 if (UNEXPECTED(guarded)) {
1010 uint32_t *guard = zend_get_property_guard(instance, name);
1011 if (!((*guard) & IN_SET)) {
1012 (*guard) |= IN_SET;
1013 variable_ptr = zend_std_write_property(instance, name, &backup, cache_slot);
1014 (*guard) &= ~IN_SET;
1015 goto exit;
1016 }
1017 }
1018
1019 variable_ptr = zend_std_write_property(instance, name, &backup, cache_slot);
1020
1021exit:
1022 zval_ptr_dtor(&backup);
1023
1024 if (variable_ptr == &backup) {
1026 }
1027
1028 return variable_ptr;
1029}
1030
1032{
1033 zval *variable_ptr, tmp;
1034 uintptr_t property_offset;
1036 uint32_t *guard = NULL;
1038
1039 property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__set != NULL), cache_slot, &prop_info);
1040
1041 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
1042try_again:
1043 variable_ptr = OBJ_PROP(zobj, property_offset);
1044
1046 bool error;
1048 error = true;
1049 } else {
1051 error = (*guard) & IN_SET;
1052 }
1053 if (error) {
1054 if ((prop_info->flags & ZEND_ACC_READONLY)
1058 variable_ptr = &EG(error_zval);
1059 goto exit;
1060 }
1063 variable_ptr = &EG(error_zval);
1064 goto exit;
1065 }
1066 }
1067 }
1068
1069 if (Z_TYPE_P(variable_ptr) != IS_UNDEF) {
1071
1072 if (prop_info) {
1073typed_property:
1074 ZVAL_COPY_VALUE(&tmp, value);
1075 // Increase refcount to prevent object from being released in __toString()
1076 GC_ADDREF(zobj);
1077 bool type_matched = zend_verify_property_type(prop_info, &tmp, property_uses_strict_types());
1078 if (UNEXPECTED(GC_DELREF(zobj) == 0)) {
1081 zval_ptr_dtor(&tmp);
1082 variable_ptr = &EG(error_zval);
1083 goto exit;
1084 }
1085 if (UNEXPECTED(!type_matched)) {
1086 zval_ptr_dtor(&tmp);
1087 variable_ptr = &EG(error_zval);
1088 goto exit;
1089 }
1091 value = &tmp;
1092 }
1093
1094found:;
1096
1097 variable_ptr = zend_assign_to_variable_ex(
1098 variable_ptr, value, IS_TMP_VAR, property_uses_strict_types(), &garbage);
1099
1100 if (garbage) {
1101 if (GC_DELREF(garbage) == 0) {
1102 zend_execute_data *execute_data = EG(current_execute_data);
1103 // Assign to result variable before calling the destructor as it may release the object
1104 if (execute_data
1105 && EX(func)
1106 && ZEND_USER_CODE(EX(func)->common.type)
1107 && EX(opline)
1108 && EX(opline)->opcode == ZEND_ASSIGN_OBJ
1109 && EX(opline)->result_type) {
1112 }
1114 } else {
1115 gc_check_possible_root_no_ref(garbage);
1116 }
1117 }
1118 goto exit;
1119 }
1121 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
1123 goto lazy_init;
1124 }
1125 }
1126 /* Writes to uninitialized typed properties bypass __set(). */
1127 goto write_std_property;
1128 }
1129 } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
1130 if (EXPECTED(zobj->properties != NULL)) {
1131 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1132 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1133 GC_DELREF(zobj->properties);
1134 }
1135 zobj->properties = zend_array_dup(zobj->properties);
1136 }
1137 if ((variable_ptr = zend_hash_find(zobj->properties, name)) != NULL) {
1139 goto found;
1140 }
1141 }
1142 } else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
1144
1145 if (!set) {
1146 if (prop_info->flags & ZEND_ACC_VIRTUAL) {
1147 zend_throw_error(NULL, "Property %s::$%s is read-only", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
1148 variable_ptr = &EG(error_zval);
1149 goto exit;
1150 }
1152 property_offset = prop_info->offset;
1153 if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1154 prop_info = NULL;
1155 }
1156 goto try_again;
1157 }
1158
1159 if (!zend_should_call_hook(prop_info, zobj)) {
1160 if (prop_info->flags & ZEND_ACC_VIRTUAL) {
1161 zend_throw_no_prop_backing_value_access(zobj->ce->name, name, /* is_read */ false);
1162 variable_ptr = &EG(error_zval);
1163 goto exit;
1164 }
1165
1166 /* Writes to backing store can only occur in hooks, and hence will always remain simple. */
1167 zend_execute_data *execute_data = EG(current_execute_data);
1168 if (cache_slot && EX(opline) && EX(opline)->opcode == ZEND_ASSIGN_OBJ && EX(opline)->op1_type == IS_UNUSED) {
1170 }
1171
1172 property_offset = prop_info->offset;
1173 if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1174 prop_info = NULL;
1175 }
1176 goto try_again;
1177 }
1178
1182 variable_ptr = &EG(error_zval);
1183 goto exit;
1184 }
1185
1186 GC_ADDREF(zobj);
1187 zend_call_known_instance_method_with_1_params(set, zobj, NULL, value);
1189
1191 goto exit;
1192 } else if (UNEXPECTED(EG(exception))) {
1193 variable_ptr = &EG(error_zval);
1194 goto exit;
1195 }
1196
1197 /* magic set */
1198 if (zobj->ce->__set) {
1199 if (!guard) {
1201 }
1202
1203 if (!((*guard) & IN_SET)) {
1204 GC_ADDREF(zobj);
1205 (*guard) |= IN_SET; /* prevent circular setting */
1206 zend_std_call_setter(zobj, name, value);
1207 (*guard) &= ~IN_SET;
1210 } else if (EXPECTED(!IS_WRONG_PROPERTY_OFFSET(property_offset))) {
1211 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
1212 return forward_write_to_lazy_object(zobj, name, value,
1213 cache_slot, /* guarded */ true);
1214 }
1215
1216 goto write_std_property;
1217 } else {
1218 /* Trigger the correct error */
1219 zend_wrong_offset(zobj->ce, name);
1221 variable_ptr = &EG(error_zval);
1222 goto exit;
1223 }
1224 } else {
1225 ZEND_ASSERT(!IS_WRONG_PROPERTY_OFFSET(property_offset));
1226 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
1227 goto lazy_init;
1228 }
1229write_std_property:
1230 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
1231 variable_ptr = OBJ_PROP(zobj, property_offset);
1232
1234 if (prop_info) {
1235 goto typed_property;
1236 }
1237
1239 } else {
1240 if (UNEXPECTED(zobj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
1241 zend_forbidden_dynamic_property(zobj->ce, name);
1242 variable_ptr = &EG(error_zval);
1243 goto exit;
1244 }
1245 if (UNEXPECTED(!(zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES))) {
1246 if (UNEXPECTED(!zend_deprecated_dynamic_property(zobj, name))) {
1247 variable_ptr = &EG(error_zval);
1248 goto exit;
1249 }
1250 }
1251
1254 }
1255 }
1256
1257exit:
1258 return variable_ptr;
1259
1260lazy_init:
1261 return forward_write_to_lazy_object(zobj, name, value, cache_slot,
1262 /* guarded */ false);
1263}
1264/* }}} */
1265
1266static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
1267{
1268 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
1269}
1270/* }}} */
1271
1273{
1274 zend_class_entry *ce = object->ce;
1275 zval tmp_offset;
1276
1277 /* arrayaccess_funcs_ptr is set if (and only if) the class implements zend_ce_arrayaccess */
1279 if (EXPECTED(funcs)) {
1280 if (offset == NULL) {
1281 /* [] construct */
1282 ZVAL_NULL(&tmp_offset);
1283 } else {
1284 ZVAL_COPY_DEREF(&tmp_offset, offset);
1285 }
1286
1287 GC_ADDREF(object);
1288 if (type == BP_VAR_IS) {
1289 zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, rv, &tmp_offset);
1290 if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
1291 OBJ_RELEASE(object);
1292 zval_ptr_dtor(&tmp_offset);
1293 return NULL;
1294 }
1295 if (!i_zend_is_true(rv)) {
1296 OBJ_RELEASE(object);
1297 zval_ptr_dtor(&tmp_offset);
1299 return &EG(uninitialized_zval);
1300 }
1302 }
1303
1304 zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, rv, &tmp_offset);
1305
1306 OBJ_RELEASE(object);
1307 zval_ptr_dtor(&tmp_offset);
1308
1309 if (UNEXPECTED(Z_TYPE_P(rv) == IS_UNDEF)) {
1310 if (UNEXPECTED(!EG(exception))) {
1311 zend_throw_error(NULL, "Undefined offset for object of type %s used as array", ZSTR_VAL(ce->name));
1312 }
1313 return NULL;
1314 }
1315 return rv;
1316 } else {
1317 zend_bad_array_access(ce);
1318 return NULL;
1319 }
1320}
1321/* }}} */
1322
1324{
1325 zend_class_entry *ce = object->ce;
1326 zval tmp_offset;
1327
1329 if (EXPECTED(funcs)) {
1330 if (!offset) {
1331 ZVAL_NULL(&tmp_offset);
1332 } else {
1333 ZVAL_COPY_DEREF(&tmp_offset, offset);
1334 }
1335 GC_ADDREF(object);
1337 OBJ_RELEASE(object);
1338 zval_ptr_dtor(&tmp_offset);
1339 } else {
1340 zend_bad_array_access(ce);
1341 }
1342}
1343/* }}} */
1344
1345// todo: make zend_std_has_dimension return bool as well
1346ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check_empty) /* {{{ */
1347{
1348 zend_class_entry *ce = object->ce;
1349 zval retval, tmp_offset;
1350 bool result;
1351
1353 if (EXPECTED(funcs)) {
1354 ZVAL_COPY_DEREF(&tmp_offset, offset);
1355 GC_ADDREF(object);
1356 zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, &retval, &tmp_offset);
1357 result = i_zend_is_true(&retval);
1359 if (check_empty && result && EXPECTED(!EG(exception))) {
1360 zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, &retval, &tmp_offset);
1361 result = i_zend_is_true(&retval);
1363 }
1364 OBJ_RELEASE(object);
1365 zval_ptr_dtor(&tmp_offset);
1366 } else {
1367 zend_bad_array_access(ce);
1368 return 0;
1369 }
1370
1371 return result;
1372}
1373/* }}} */
1374
1376{
1377 zval *retval = NULL;
1378 uintptr_t property_offset;
1380
1381#if DEBUG_OBJECT_HANDLERS
1382 fprintf(stderr, "Ptr object #%d property: %s\n", zobj->handle, ZSTR_VAL(name));
1383#endif
1384
1385 property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__get != NULL), cache_slot, &prop_info);
1386
1387 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
1388 retval = OBJ_PROP(zobj, property_offset);
1390 if (EXPECTED(!zobj->ce->__get) ||
1393 if (UNEXPECTED(zend_lazy_object_must_init(zobj) && (Z_PROP_FLAG_P(retval) & IS_PROP_LAZY))) {
1395 if (!zobj) {
1396 return &EG(error_zval);
1397 }
1398
1399 return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot);
1400 }
1401 if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
1402 if (prop_info) {
1403 zend_typed_property_uninitialized_access(prop_info, name);
1404 retval = &EG(error_zval);
1405 } else {
1406 zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
1407 /* An error handler may set the property */
1408 if (EXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
1410 }
1411 }
1414 retval = NULL;
1415 }
1416 } else if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
1418 }
1419 } else {
1420 /* we do have getter - fail and let it try again with usual get/set */
1421 retval = NULL;
1422 }
1425 retval = NULL;
1426 }
1427 }
1428 } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
1429 if (EXPECTED(zobj->properties)) {
1430 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1431 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1432 GC_DELREF(zobj->properties);
1433 }
1434 zobj->properties = zend_array_dup(zobj->properties);
1435 }
1436 if (EXPECTED((retval = zend_hash_find(zobj->properties, name)) != NULL)) {
1437 return retval;
1438 }
1439 }
1440 if (EXPECTED(!zobj->ce->__get) ||
1442 if (UNEXPECTED(zobj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
1443 zend_forbidden_dynamic_property(zobj->ce, name);
1444 return &EG(error_zval);
1445 }
1446 if (UNEXPECTED(!(zobj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES))) {
1447 if (UNEXPECTED(!zend_deprecated_dynamic_property(zobj, name))) {
1448 return &EG(error_zval);
1449 }
1450 }
1451 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
1453 if (!zobj) {
1454 return &EG(error_zval);
1455 }
1456
1457 return zend_std_get_property_ptr_ptr(zobj, name, type, cache_slot);
1458 }
1459 if (UNEXPECTED(!zobj->properties)) {
1461 }
1462 if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
1463 zend_error(E_WARNING, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
1464 }
1465 retval = zend_hash_add(zobj->properties, name, &EG(uninitialized_zval));
1466 }
1467 } else if (!IS_HOOKED_PROPERTY_OFFSET(property_offset) && zobj->ce->__get == NULL) {
1468 retval = &EG(error_zval);
1469 }
1470
1471 return retval;
1472}
1473/* }}} */
1474
1476{
1477 uintptr_t property_offset;
1479 uint32_t *guard = NULL;
1480
1481 property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__unset != NULL), cache_slot, &prop_info);
1482
1483 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
1484 zval *slot = OBJ_PROP(zobj, property_offset);
1485
1487 bool error;
1488 if (Z_TYPE_P(slot) != IS_UNDEF || Z_PROP_FLAG_P(slot) & IS_PROP_UNINIT || !zobj->ce->__unset) {
1489 error = true;
1490 } else {
1492 error = (*guard) & IN_UNSET;
1493 }
1494 if (error) {
1495 if ((prop_info->flags & ZEND_ACC_READONLY)
1496 && Z_TYPE_P(slot) != IS_UNDEF
1497 && !(Z_PROP_FLAG_P(slot) & IS_PROP_REINITABLE)) {
1498 zend_readonly_property_unset_error(prop_info->ce, name);
1499 return;
1500 }
1503 return;
1504 }
1505 }
1506 }
1507
1508 if (Z_TYPE_P(slot) != IS_UNDEF) {
1509 if (UNEXPECTED(Z_ISREF_P(slot)) &&
1510 (ZEND_DEBUG || ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(slot)))) {
1511 if (prop_info) {
1513 }
1514 }
1515 zval tmp;
1516 ZVAL_COPY_VALUE(&tmp, slot);
1517 ZVAL_UNDEF(slot);
1518 zval_ptr_dtor(&tmp);
1519 if (zobj->properties) {
1520 HT_FLAGS(zobj->properties) |= HASH_FLAG_HAS_EMPTY_IND;
1521 }
1522 return;
1523 }
1525 if (UNEXPECTED(zend_lazy_object_must_init(zobj) && (Z_PROP_FLAG_P(slot) & IS_PROP_LAZY))) {
1527 if (!zobj) {
1528 return;
1529 }
1530 zend_std_unset_property(zobj, name, cache_slot);
1531 return;
1532 }
1533
1534 /* Reset the IS_PROP_UNINIT flag, if it exists and bypass __unset(). */
1535 Z_PROP_FLAG_P(slot) = 0;
1536 return;
1537 }
1538 } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))
1539 && EXPECTED(zobj->properties != NULL)) {
1540 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
1541 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
1542 GC_DELREF(zobj->properties);
1543 }
1544 zobj->properties = zend_array_dup(zobj->properties);
1545 }
1546 if (EXPECTED(zend_hash_del(zobj->properties, name) != FAILURE)) {
1547 return;
1548 }
1549 } else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
1550 zend_throw_error(NULL, "Cannot unset hooked property %s::$%s",
1551 ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
1552 return;
1553 } else if (UNEXPECTED(EG(exception))) {
1554 return;
1555 }
1556
1557 /* magic unset */
1558 if (zobj->ce->__unset) {
1559 if (!guard) {
1561 }
1562 if (!((*guard) & IN_UNSET)) {
1563 /* have unsetter - try with it! */
1564 (*guard) |= IN_UNSET; /* prevent circular unsetting */
1565 zend_std_call_unsetter(zobj, name);
1566 (*guard) &= ~IN_UNSET;
1567 return;
1568 } else if (UNEXPECTED(IS_WRONG_PROPERTY_OFFSET(property_offset))) {
1569 /* Trigger the correct error */
1570 zend_wrong_offset(zobj->ce, name);
1572 return;
1573 } else {
1574 /* Nothing to do: The property already does not exist. */
1575 }
1576 }
1577
1578 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
1580 if (!zobj) {
1581 return;
1582 }
1583
1584 if (UNEXPECTED(guard)) {
1586 if (!((*guard) & IN_UNSET)) {
1587 (*guard) |= IN_UNSET;
1588 zend_std_unset_property(zobj, name, cache_slot);
1589 (*guard) &= ~IN_UNSET;
1590 return;
1591 }
1592 }
1593
1594 zend_std_unset_property(zobj, name, cache_slot);
1595 return;
1596 }
1597}
1598/* }}} */
1599
1601{
1602 zend_class_entry *ce = object->ce;
1603 zval tmp_offset;
1604
1606 if (EXPECTED(funcs)) {
1607 ZVAL_COPY_DEREF(&tmp_offset, offset);
1608 GC_ADDREF(object);
1609 zend_call_known_instance_method_with_1_params(funcs->zf_offsetunset, object, NULL, &tmp_offset);
1610 OBJ_RELEASE(object);
1611 zval_ptr_dtor(&tmp_offset);
1612 } else {
1613 zend_bad_array_access(ce);
1614 }
1615}
1616/* }}} */
1617
1618static zend_never_inline zend_function *zend_get_parent_private_method(zend_class_entry *scope, zend_class_entry *ce, zend_string *function_name) /* {{{ */
1619{
1620 zval *func;
1622
1623 if (scope != ce && scope && is_derived_class(ce, scope)) {
1624 func = zend_hash_find(&scope->function_table, function_name);
1625 if (func != NULL) {
1626 fbc = Z_FUNC_P(func);
1627 if ((fbc->common.fn_flags & ZEND_ACC_PRIVATE)
1628 && fbc->common.scope == scope) {
1629 return fbc;
1630 }
1631 }
1632 }
1633 return NULL;
1634}
1635/* }}} */
1636
1637/* Ensures that we're allowed to call a protected method.
1638 */
1640{
1641 const zend_class_entry *fbc_scope = ce;
1642
1643 /* Is the context that's calling the function, the same as one of
1644 * the function's parents?
1645 */
1646 while (fbc_scope) {
1647 if (fbc_scope==scope) {
1648 return 1;
1649 }
1650 fbc_scope = fbc_scope->parent;
1651 }
1652
1653 /* Is the function's scope the same as our current object context,
1654 * or any of the parents of our context?
1655 */
1656 while (scope) {
1657 if (scope==ce) {
1658 return 1;
1659 }
1660 scope = scope->parent;
1661 }
1662 return 0;
1663}
1664/* }}} */
1665
1666ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static) /* {{{ */
1667{
1668 size_t mname_len;
1670 zend_function *fbc = is_static ? ce->__callstatic : ce->__call;
1671 /* We use non-NULL value to avoid useless run_time_cache allocation.
1672 * The low bit must be zero, to not be interpreted as a MAP_PTR offset.
1673 */
1674 static const void *dummy = (void*)(intptr_t)2;
1675 static const zend_arg_info arg_info[1] = {{0}};
1676
1678
1679 if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
1680 func = &EG(trampoline).op_array;
1681 } else {
1682 func = ecalloc(1, sizeof(zend_op_array));
1683 }
1684
1685 func->type = ZEND_USER_FUNCTION;
1686 func->arg_flags[0] = 0;
1687 func->arg_flags[1] = 0;
1688 func->arg_flags[2] = 0;
1693 /* Attributes outlive the trampoline because they are created by the compiler. */
1694 func->attributes = fbc->common.attributes;
1695 if (is_static) {
1696 func->fn_flags |= ZEND_ACC_STATIC;
1697 }
1698 func->opcodes = &EG(call_trampoline_op);
1699 ZEND_MAP_PTR_INIT(func->run_time_cache, (void**)dummy);
1700 func->scope = fbc->common.scope;
1701 /* reserve space for arguments, local and temporary variables */
1702 /* EG(trampoline) is reused from other places, like FFI (e.g. zend_ffi_cdata_get_closure()) where
1703 * it is used as an internal function. It may set fields that don't belong to common, thus
1704 * modifying zend_op_array specific data, most significantly last_var. We need to reset this
1705 * value so that it doesn't contain garbage when the engine allocates space for the next stack
1706 * frame. This didn't cause any issues until now due to "lucky" structure layout. */
1707 func->last_var = 0;
1708 uint32_t min_T = 2 + ZEND_OBSERVER_ENABLED;
1709 func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, min_T) : min_T;
1710 func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : ZSTR_EMPTY_ALLOC();
1711 func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0;
1712 func->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0;
1713
1714 //??? keep compatibility for "\0" characters
1715 //??? see: Zend/tests/bug46238.phpt
1716 if (UNEXPECTED((mname_len = strlen(ZSTR_VAL(method_name))) != ZSTR_LEN(method_name))) {
1717 func->function_name = zend_string_init(ZSTR_VAL(method_name), mname_len, 0);
1718 } else {
1719 func->function_name = zend_string_copy(method_name);
1720 }
1721
1722 func->prototype = NULL;
1723 func->prop_info = NULL;
1724 func->num_args = 0;
1725 func->required_num_args = 0;
1726 func->arg_info = (zend_arg_info *) arg_info;
1727
1728 return (zend_function*)func;
1729}
1730/* }}} */
1731
1732static ZEND_FUNCTION(zend_parent_hook_get_trampoline)
1733{
1735 zend_string *prop_name = EX(func)->internal_function.reserved[0];
1736
1737 if (UNEXPECTED(ZEND_NUM_ARGS() != 0)) {
1739 goto clean;
1740 }
1741
1742 zval rv;
1743 zval *retval = obj->handlers->read_property(obj, prop_name, BP_VAR_R, NULL, &rv);
1744 if (retval == &rv) {
1746 } else {
1748 }
1749
1750clean:
1751 zend_string_release(EX(func)->common.function_name);
1753 EX(func) = NULL;
1754}
1755
1756static ZEND_FUNCTION(zend_parent_hook_set_trampoline)
1757{
1759 zend_string *prop_name = EX(func)->internal_function.reserved[0];
1760
1761 zval *value;
1762
1765 ZEND_PARSE_PARAMETERS_END_EX(goto clean);
1766
1767 RETVAL_COPY(obj->handlers->write_property(obj, prop_name, value, NULL));
1768
1769clean:
1770 zend_string_release(EX(func)->common.function_name);
1772 EX(func) = NULL;
1773}
1774
1778{
1779 static const zend_arg_info arg_info[1] = {{0}};
1781 if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
1782 func = &EG(trampoline);
1783 } else {
1784 func = (zend_function *)(uintptr_t)ecalloc(1, sizeof(zend_internal_function));
1785 }
1787 func->common.arg_flags[0] = 0;
1788 func->common.arg_flags[1] = 0;
1789 func->common.arg_flags[2] = 0;
1790 func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
1791 func->common.function_name = zend_string_concat3(
1792 "$", 1, ZSTR_VAL(prop_name), ZSTR_LEN(prop_name),
1793 kind == ZEND_PROPERTY_HOOK_GET ? "::get" : "::set", 5);
1794 /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
1795 uint32_t args = kind == ZEND_PROPERTY_HOOK_GET ? 0 : 1;
1796 func->common.num_args = args;
1797 func->common.required_num_args = args;
1798 func->common.scope = prop_info->ce;
1799 func->common.prototype = NULL;
1800 func->common.prop_info = prop_info;
1801 func->common.arg_info = (zend_arg_info *) arg_info;
1802 func->internal_function.handler = kind == ZEND_PROPERTY_HOOK_GET
1803 ? ZEND_FN(zend_parent_hook_get_trampoline)
1804 : ZEND_FN(zend_parent_hook_set_trampoline);
1805 func->internal_function.module = NULL;
1806
1807 func->internal_function.reserved[0] = prop_name;
1808 func->internal_function.reserved[1] = NULL;
1809
1810 return func;
1811}
1812
1813static zend_always_inline zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
1814{
1815 return zend_get_call_trampoline_func(ce, method_name, 0);
1816}
1817/* }}} */
1818
1819static ZEND_COLD zend_never_inline void zend_bad_method_call(zend_function *fbc, zend_string *method_name, zend_class_entry *scope) /* {{{ */
1820{
1821 zend_throw_error(NULL, "Call to %s method %s::%s() from %s%s",
1822 zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(method_name),
1823 scope ? "scope " : "global scope",
1824 scope ? ZSTR_VAL(scope->name) : ""
1825 );
1826}
1827/* }}} */
1828
1829static ZEND_COLD zend_never_inline void zend_abstract_method_call(zend_function *fbc) /* {{{ */
1830{
1831 zend_throw_error(NULL, "Cannot call abstract method %s::%s()",
1832 ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
1833}
1834/* }}} */
1835
1836ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
1837{
1838 zend_object *zobj = *obj_ptr;
1839 zval *func;
1841 zend_string *lc_method_name;
1843 ALLOCA_FLAG(use_heap);
1844
1845 if (EXPECTED(key != NULL)) {
1846 lc_method_name = Z_STR_P(key);
1847#ifdef ZEND_ALLOCA_MAX_SIZE
1848 use_heap = 0;
1849#endif
1850 } else {
1851 ZSTR_ALLOCA_ALLOC(lc_method_name, ZSTR_LEN(method_name), use_heap);
1852 zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
1853 }
1854
1855 if (UNEXPECTED((func = zend_hash_find(&zobj->ce->function_table, lc_method_name)) == NULL)) {
1856 if (UNEXPECTED(!key)) {
1857 ZSTR_ALLOCA_FREE(lc_method_name, use_heap);
1858 }
1859 if (zobj->ce->__call) {
1860 return zend_get_user_call_function(zobj->ce, method_name);
1861 } else {
1862 return NULL;
1863 }
1864 }
1865
1866 fbc = Z_FUNC_P(func);
1867
1868 /* Check access level */
1869 if (fbc->op_array.fn_flags & (ZEND_ACC_CHANGED|ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
1871
1872 if (fbc->common.scope != scope) {
1873 if (fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
1874 zend_function *updated_fbc = zend_get_parent_private_method(scope, zobj->ce, lc_method_name);
1875
1876 if (EXPECTED(updated_fbc != NULL)) {
1877 fbc = updated_fbc;
1878 goto exit;
1879 } else if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
1880 goto exit;
1881 }
1882 }
1883 if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
1885 if (zobj->ce->__call) {
1886 fbc = zend_get_user_call_function(zobj->ce, method_name);
1887 } else {
1888 zend_bad_method_call(fbc, method_name, scope);
1889 fbc = NULL;
1890 }
1891 }
1892 }
1893 }
1894
1895exit:
1896 if (fbc && UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1897 zend_abstract_method_call(fbc);
1898 fbc = NULL;
1899 }
1900 if (UNEXPECTED(!key)) {
1901 ZSTR_ALLOCA_FREE(lc_method_name, use_heap);
1902 }
1903 return fbc;
1904}
1905/* }}} */
1906
1907static zend_always_inline zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
1908{
1909 return zend_get_call_trampoline_func(ce, method_name, 1);
1910}
1911/* }}} */
1912
1913static zend_always_inline zend_function *get_static_method_fallback(
1914 zend_class_entry *ce, zend_string *function_name)
1915{
1917 if (ce->__call &&
1918 (object = zend_get_this_object(EG(current_execute_data))) != NULL &&
1919 instanceof_function(object->ce, ce)) {
1920 /* Call the top-level defined __call().
1921 * see: tests/classes/__call_004.phpt */
1922
1923 ZEND_ASSERT(object->ce->__call);
1924 return zend_get_user_call_function(object->ce, function_name);
1925 } else if (ce->__callstatic) {
1926 return zend_get_user_callstatic_function(ce, function_name);
1927 } else {
1928 return NULL;
1929 }
1930}
1931
1933{
1934 zend_string *lc_function_name;
1935 if (EXPECTED(key != NULL)) {
1936 lc_function_name = Z_STR_P(key);
1937 } else {
1938 lc_function_name = zend_string_tolower(function_name);
1939 }
1940
1942 zval *func = zend_hash_find(&ce->function_table, lc_function_name);
1943 if (EXPECTED(func)) {
1944 fbc = Z_FUNC_P(func);
1945 if (!(fbc->op_array.fn_flags & ZEND_ACC_PUBLIC)) {
1947 if (UNEXPECTED(fbc->common.scope != scope)) {
1948 if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
1950 zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
1951 if (!fallback_fbc) {
1952 zend_bad_method_call(fbc, function_name, scope);
1953 }
1954 fbc = fallback_fbc;
1955 }
1956 }
1957 }
1958 } else {
1959 fbc = get_static_method_fallback(ce, function_name);
1960 }
1961
1962 if (UNEXPECTED(!key)) {
1963 zend_string_release_ex(lc_function_name, 0);
1964 }
1965
1966 if (EXPECTED(fbc)) {
1967 if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1968 zend_abstract_method_call(fbc);
1969 goto fail;
1970 } else if (UNEXPECTED(fbc->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
1972 "Calling static trait method %s::%s is deprecated, "
1973 "it should only be called on a class using the trait",
1974 ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
1975 if (EG(exception)) {
1976 goto fail;
1977 }
1978 }
1979 }
1980
1981 return fbc;
1982
1983 fail:
1984 if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
1985 zend_string_release_ex(fbc->common.function_name, 0);
1987 }
1988
1989 return NULL;
1990}
1991/* }}} */
1992
1994{
1995 int i;
1996 zval *p;
1997
1998 if (class_type->default_static_members_count && !CE_STATIC_MEMBERS(class_type)) {
1999 if (class_type->parent) {
2000 zend_class_init_statics(class_type->parent);
2001 }
2002
2003 ZEND_MAP_PTR_SET(class_type->static_members_table, emalloc(sizeof(zval) * class_type->default_static_members_count));
2004 for (i = 0; i < class_type->default_static_members_count; i++) {
2005 p = &class_type->default_static_members_table[i];
2006 if (Z_TYPE_P(p) == IS_INDIRECT) {
2007 zval *q = &CE_STATIC_MEMBERS(class_type->parent)[i];
2008 ZVAL_DEINDIRECT(q);
2009 ZVAL_INDIRECT(&CE_STATIC_MEMBERS(class_type)[i], q);
2010 } else {
2011 ZVAL_COPY_OR_DUP(&CE_STATIC_MEMBERS(class_type)[i], p);
2012 }
2013 }
2014 }
2015} /* }}} */
2016
2018{
2019 zval *ret;
2020 zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, property_name);
2021 *property_info_ptr = property_info;
2022
2023 if (UNEXPECTED(property_info == NULL)) {
2024 goto undeclared_property;
2025 }
2026
2027 if (!(property_info->flags & ZEND_ACC_PUBLIC)) {
2028 zend_class_entry *scope = get_fake_or_executed_scope();
2029 if (property_info->ce != scope) {
2030 if (UNEXPECTED(property_info->flags & ZEND_ACC_PRIVATE)
2031 || UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
2032 if (type != BP_VAR_IS) {
2033 zend_bad_property_access(property_info, ce, property_name);
2034 }
2035 return NULL;
2036 }
2037 }
2038 }
2039
2040 if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) {
2041undeclared_property:
2042 if (type != BP_VAR_IS) {
2043 zend_throw_error(NULL, "Access to undeclared static property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
2044 }
2045 return NULL;
2046 }
2047
2050 return NULL;
2051 }
2052 }
2053
2054 /* Ensure static properties are initialized. */
2055 if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
2057 }
2058
2059 ret = CE_STATIC_MEMBERS(ce) + property_info->offset;
2061
2062 if (UNEXPECTED((type == BP_VAR_R || type == BP_VAR_RW)
2063 && Z_TYPE_P(ret) == IS_UNDEF && ZEND_TYPE_IS_SET(property_info->type))) {
2064 zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
2065 ZSTR_VAL(property_info->ce->name), ZSTR_VAL(property_name));
2066 return NULL;
2067 }
2068
2069 if (UNEXPECTED(ce->ce_flags & ZEND_ACC_TRAIT)) {
2071 "Accessing static trait property %s::$%s is deprecated, "
2072 "it should only be accessed on a class using the trait",
2073 ZSTR_VAL(property_info->ce->name), ZSTR_VAL(property_name));
2074 }
2075
2076 return ret;
2077}
2078/* }}} */
2079
2085
2087{
2088 zend_throw_error(NULL, "Attempt to unset static property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
2089 return 0;
2090}
2091/* }}} */
2092
2093static ZEND_COLD zend_never_inline void zend_bad_constructor_call(zend_function *constructor, zend_class_entry *scope) /* {{{ */
2094{
2095 if (scope) {
2096 zend_throw_error(NULL, "Call to %s %s::%s() from scope %s",
2097 zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name),
2098 ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name)
2099 );
2100 } else {
2101 zend_throw_error(NULL, "Call to %s %s::%s() from global scope", zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name));
2102 }
2103}
2104/* }}} */
2105
2107{
2108 zend_function *constructor = zobj->ce->constructor;
2109
2110 if (constructor) {
2111 if (UNEXPECTED(!(constructor->op_array.fn_flags & ZEND_ACC_PUBLIC))) {
2112 zend_class_entry *scope = get_fake_or_executed_scope();
2113 if (UNEXPECTED(constructor->common.scope != scope)) {
2114 if (UNEXPECTED(constructor->op_array.fn_flags & ZEND_ACC_PRIVATE)
2116 zend_bad_constructor_call(constructor, scope);
2117 zend_object_store_ctor_failed(zobj);
2118 constructor = NULL;
2119 }
2120 }
2121 }
2122 }
2123
2124 return constructor;
2125}
2126/* }}} */
2127
2129{
2130 zend_object *zobj1, *zobj2;
2131
2132 if (zend_objects_check_stack_limit()) {
2133 zend_throw_error(NULL, "Maximum call stack size reached during object comparison");
2134 return ZEND_UNCOMPARABLE;
2135 }
2136
2137 if (Z_TYPE_P(o1) != Z_TYPE_P(o2)) {
2138 /* Object and non-object */
2139 zval *object;
2140 zval *value;
2141 zval casted;
2142 bool object_lhs;
2143 if (Z_TYPE_P(o1) == IS_OBJECT) {
2144 object = o1;
2145 value = o2;
2146 object_lhs = true;
2147 } else {
2148 object = o2;
2149 value = o1;
2150 object_lhs = false;
2151 }
2153 uint8_t target_type = (Z_TYPE_P(value) == IS_FALSE || Z_TYPE_P(value) == IS_TRUE)
2154 ? _IS_BOOL : Z_TYPE_P(value);
2155 if (Z_OBJ_HT_P(object)->cast_object(Z_OBJ_P(object), &casted, target_type) == FAILURE) {
2156 // TODO: Less crazy.
2157 if (target_type == IS_LONG || target_type == IS_DOUBLE) {
2158 zend_error(E_NOTICE, "Object of class %s could not be converted to %s",
2159 ZSTR_VAL(Z_OBJCE_P(object)->name), zend_get_type_by_const(target_type));
2160 if (target_type == IS_LONG) {
2161 ZVAL_LONG(&casted, 1);
2162 } else {
2163 ZVAL_DOUBLE(&casted, 1.0);
2164 }
2165 } else {
2166 return object_lhs ? 1 : -1;
2167 }
2168 }
2169 int ret = object_lhs ? zend_compare(&casted, value) : zend_compare(value, &casted);
2170 zval_ptr_dtor(&casted);
2171 return ret;
2172 }
2173
2174 zobj1 = Z_OBJ_P(o1);
2175 zobj2 = Z_OBJ_P(o2);
2176
2177 if (zobj1 == zobj2) {
2178 return 0; /* the same object */
2179 }
2180 if (zobj1->ce != zobj2->ce) {
2181 return ZEND_UNCOMPARABLE; /* different classes */
2182 }
2183 if (!zobj1->properties && !zobj2->properties
2184 && !zend_object_is_lazy(zobj1) && !zend_object_is_lazy(zobj2)) {
2185 zend_property_info *info;
2186 int i;
2187
2188 if (!zobj1->ce->default_properties_count) {
2189 return 0;
2190 }
2191
2192 /* It's enough to protect only one of the objects.
2193 * The second one may be referenced from the first and this may cause
2194 * false recursion detection.
2195 */
2196 /* use bitwise OR to make only one conditional jump */
2197 if (UNEXPECTED(Z_IS_RECURSIVE_P(o1))) {
2198 zend_throw_error(NULL, "Nesting level too deep - recursive dependency?");
2199 return ZEND_UNCOMPARABLE;
2200 }
2202
2203 for (i = 0; i < zobj1->ce->default_properties_count; i++) {
2204 zval *p1, *p2;
2205
2206 info = zobj1->ce->properties_info_table[i];
2207
2208 if (!info) {
2209 continue;
2210 }
2211
2212 p1 = OBJ_PROP(zobj1, info->offset);
2213 p2 = OBJ_PROP(zobj2, info->offset);
2214
2215 if (Z_TYPE_P(p1) != IS_UNDEF) {
2216 if (Z_TYPE_P(p2) != IS_UNDEF) {
2217 int ret;
2218
2219 ret = zend_compare(p1, p2);
2220 if (ret != 0) {
2222 return ret;
2223 }
2224 } else {
2226 return 1;
2227 }
2228 } else {
2229 if (Z_TYPE_P(p2) != IS_UNDEF) {
2231 return 1;
2232 }
2233 }
2234 }
2235
2237 return 0;
2238 } else {
2240 zend_std_get_properties_ex(zobj1),
2241 zend_std_get_properties_ex(zobj2));
2242 }
2243}
2244/* }}} */
2245
2247{
2248 return ZEND_UNCOMPARABLE;
2249}
2250
2251// todo: make zend_std_has_property return bool as well
2252ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has_set_exists, void **cache_slot) /* {{{ */
2253{
2254 bool result;
2255 zval *value = NULL;
2256 uintptr_t property_offset;
2258
2259 property_offset = zend_get_property_offset(zobj->ce, name, 1, cache_slot, &prop_info);
2260
2261 if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
2262try_again:
2263 value = OBJ_PROP(zobj, property_offset);
2264 if (Z_TYPE_P(value) != IS_UNDEF) {
2265 goto found;
2266 }
2268 /* Skip __isset() for uninitialized typed properties */
2269 goto lazy_init;
2270 }
2271 } else if (EXPECTED(IS_DYNAMIC_PROPERTY_OFFSET(property_offset))) {
2272 if (EXPECTED(zobj->properties != NULL)) {
2273 if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(property_offset)) {
2274 uintptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(property_offset);
2275
2276 if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2277 Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2278
2279 if (EXPECTED(p->key == name) ||
2280 (EXPECTED(p->h == ZSTR_H(name)) &&
2281 EXPECTED(p->key != NULL) &&
2282 EXPECTED(zend_string_equal_content(p->key, name)))) {
2283 value = &p->val;
2284 goto found;
2285 }
2286 }
2287 CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2288 }
2289 value = zend_hash_find(zobj->properties, name);
2290 if (value) {
2291 if (cache_slot) {
2292 uintptr_t idx = (char*)value - (char*)zobj->properties->arData;
2293 CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2294 }
2295found:
2296 if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY) {
2298 } else if (has_set_exists < ZEND_PROPERTY_NOT_EMPTY) {
2299 ZEND_ASSERT(has_set_exists == ZEND_PROPERTY_ISSET);
2301 result = (Z_TYPE_P(value) != IS_NULL);
2302 } else {
2303 ZEND_ASSERT(has_set_exists == ZEND_PROPERTY_EXISTS);
2304 result = true;
2305 }
2306 goto exit;
2307 }
2308 }
2309 } else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
2311
2312 if (has_set_exists == ZEND_PROPERTY_EXISTS) {
2313 if (prop_info->flags & ZEND_ACC_VIRTUAL) {
2314 return true;
2315 }
2316 property_offset = prop_info->offset;
2317 goto try_again;
2318 }
2319
2320 if (!get) {
2321 if (prop_info->flags & ZEND_ACC_VIRTUAL) {
2322 zend_throw_error(NULL, "Property %s::$%s is write-only",
2323 ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
2324 return 0;
2325 } else {
2326 property_offset = prop_info->offset;
2327 goto try_again;
2328 }
2329 }
2330
2331 zval rv;
2332 if (!zend_call_get_hook(prop_info, name, get, zobj, &rv)) {
2333 if (EG(exception)) {
2334 return 0;
2335 }
2336 property_offset = prop_info->offset;
2337 goto try_again;
2338 }
2339
2340 if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY) {
2342 } else {
2343 ZEND_ASSERT(has_set_exists == ZEND_PROPERTY_ISSET);
2344 result = Z_TYPE(rv) != IS_NULL
2345 && (Z_TYPE(rv) != IS_REFERENCE || Z_TYPE_P(Z_REFVAL(rv)) != IS_NULL);
2346 }
2347 zval_ptr_dtor(&rv);
2348 return result;
2349 } else if (UNEXPECTED(EG(exception))) {
2350 result = false;
2351 goto exit;
2352 }
2353
2354 if (!zobj->ce->__isset) {
2355 goto lazy_init;
2356 }
2357
2358 result = false;
2359 if (has_set_exists != ZEND_PROPERTY_EXISTS) {
2360 uint32_t *guard = zend_get_property_guard(zobj, name);
2361
2362 if (!((*guard) & IN_ISSET)) {
2363 zval rv;
2364
2365 /* have issetter - try with it! */
2366 GC_ADDREF(zobj);
2367 (*guard) |= IN_ISSET; /* prevent circular getting */
2368 zend_std_call_issetter(zobj, name, &rv);
2370 zval_ptr_dtor(&rv);
2371 if (has_set_exists == ZEND_PROPERTY_NOT_EMPTY && result) {
2372 if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) {
2373 (*guard) |= IN_GET;
2374 zend_std_call_getter(zobj, name, &rv);
2375 (*guard) &= ~IN_GET;
2376 result = i_zend_is_true(&rv);
2377 zval_ptr_dtor(&rv);
2378 } else {
2379 result = false;
2380 }
2381 }
2382 (*guard) &= ~IN_ISSET;
2384 } else {
2385 goto lazy_init;
2386 }
2387 }
2388
2389exit:
2390 return result;
2391
2392lazy_init:
2393 if (UNEXPECTED(zend_lazy_object_must_init(zobj))) {
2394 if (!value || (Z_PROP_FLAG_P(value) & IS_PROP_LAZY)) {
2396 if (!zobj) {
2397 result = 0;
2398 goto exit;
2399 }
2400
2401 if (UNEXPECTED(zobj->ce->__isset)) {
2402 uint32_t *guard = zend_get_property_guard(zobj, name);
2403 if (!((*guard) & IN_ISSET)) {
2404 (*guard) |= IN_ISSET;
2405 result = zend_std_has_property(zobj, name, has_set_exists, cache_slot);
2406 (*guard) &= ~IN_ISSET;
2407 return result;
2408 }
2409 }
2410
2411 return zend_std_has_property(zobj, name, has_set_exists, cache_slot);
2412 }
2413 }
2414
2415 result = 0;
2416 goto exit;
2417}
2418/* }}} */
2419
2421{
2422 return zend_string_copy(zobj->ce->name);
2423}
2424/* }}} */
2425
2427{
2428 switch (type) {
2429 case IS_STRING: {
2430 zend_class_entry *ce = readobj->ce;
2431 if (ce->__tostring) {
2432 zval retval;
2433 GC_ADDREF(readobj);
2434 zend_call_known_instance_method_with_0_params(ce->__tostring, readobj, &retval);
2435 zend_object_release(readobj);
2436 if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
2437 ZVAL_COPY_VALUE(writeobj, &retval);
2438 return SUCCESS;
2439 }
2441 if (!EG(exception)) {
2442 zend_throw_error(NULL, "Method %s::__toString() must return a string value", ZSTR_VAL(ce->name));
2443 }
2444 }
2445 return FAILURE;
2446 }
2447 case _IS_BOOL:
2448 ZVAL_TRUE(writeobj);
2449 return SUCCESS;
2450 default:
2451 return FAILURE;
2452 }
2453}
2454/* }}} */
2455
2456ZEND_API zend_result zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) /* {{{ */
2457{
2458 zend_class_entry *ce = obj->ce;
2459 zval *func = zend_hash_find_known_hash(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE));
2460
2461 if (func == NULL) {
2462 return FAILURE;
2463 }
2464 *fptr_ptr = Z_FUNC_P(func);
2465
2466 *ce_ptr = ce;
2467 if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) {
2468 if (obj_ptr) {
2469 *obj_ptr = NULL;
2470 }
2471 } else {
2472 if (obj_ptr) {
2473 *obj_ptr = obj;
2474 }
2475 }
2476 return SUCCESS;
2477}
2478/* }}} */
2479
2481 HashTable *ht;
2482 switch (purpose) {
2484 if (obj->handlers->get_debug_info) {
2485 int is_temp;
2486 ht = obj->handlers->get_debug_info(obj, &is_temp);
2487 if (ht && !is_temp) {
2489 }
2490 return ht;
2491 }
2496 if (obj->ce->num_hooked_props) {
2498 }
2499 ht = obj->handlers->get_properties(obj);
2500 if (ht) {
2502 }
2503 return ht;
2506 if (ht) {
2508 }
2509 return ht;
2511 if (zend_object_is_lazy(obj)
2512 && !zend_lazy_object_initialize_on_serialize(obj)) {
2514 } else {
2515 ht = obj->handlers->get_properties(obj);
2516 }
2517 if (ht) {
2519 }
2520 return ht;
2521 }
2522 default:
2524 return NULL;
2525 }
2526}
2527
2529 zend_object *zobj = Z_OBJ_P(obj);
2530
2531 if (zobj->handlers->get_properties_for) {
2532 return zobj->handlers->get_properties_for(zobj, purpose);
2533 }
2534
2535 return zend_std_get_properties_for(zobj, purpose);
2536}
2537
2539 0, /* offset */
2540
2541 zend_object_std_dtor, /* free_obj */
2542 zend_objects_destroy_object, /* dtor_obj */
2543 zend_objects_clone_obj, /* clone_obj */
2544
2545 zend_std_read_property, /* read_property */
2546 zend_std_write_property, /* write_property */
2547 zend_std_read_dimension, /* read_dimension */
2548 zend_std_write_dimension, /* write_dimension */
2549 zend_std_get_property_ptr_ptr, /* get_property_ptr_ptr */
2550 zend_std_has_property, /* has_property */
2551 zend_std_unset_property, /* unset_property */
2552 zend_std_has_dimension, /* has_dimension */
2553 zend_std_unset_dimension, /* unset_dimension */
2554 zend_std_get_properties, /* get_properties */
2555 zend_std_get_method, /* get_method */
2556 zend_std_get_constructor, /* get_constructor */
2557 zend_std_get_class_name, /* get_class_name */
2558 zend_std_cast_object_tostring, /* cast_object */
2559 NULL, /* count_elements */
2560 zend_std_get_debug_info, /* get_debug_info */
2561 zend_std_get_closure, /* get_closure */
2562 zend_std_get_gc, /* get_gc */
2563 NULL, /* do_operation */
2564 zend_std_compare_objects, /* compare */
2565 NULL, /* get_properties_for */
2566};
bool exception
Definition assert.c:30
fprintf($stream, string $format, mixed ... $values)
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type kind
Definition ffi.c:4363
void * ptr
Definition ffi.c:3814
HashTable * ht
Definition ffi.c:4838
zend_long offset
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
zend_stack handlers
Definition php_output.h:139
reflection_object_handlers write_property
unsigned char key[REFLECTION_KEY_LEN]
bool fail
Definition session.c:1065
zval rv
Definition session.c:1024
p
Definition session.c:1105
zend_function * __debugInfo
Definition zend.h:182
zend_object *(* create_object)(zend_class_entry *class_type)
Definition zend.h:195
zend_function * __tostring
Definition zend.h:181
zval * default_static_members_table
Definition zend.h:161
uint32_t num_hooked_props
Definition zend.h:207
HashTable properties_info
Definition zend.h:164
zend_string * name
Definition zend.h:149
zend_function * __call
Definition zend.h:179
zend_class_arrayaccess_funcs * arrayaccess_funcs_ptr
Definition zend.h:191
uint32_t ce_flags
Definition zend.h:156
int default_properties_count
Definition zend.h:158
int default_static_members_count
Definition zend.h:159
struct _zend_property_info ** properties_info_table
Definition zend.h:170
zend_class_entry * parent
Definition zend.h:152
HashTable function_table
Definition zend.h:163
const zend_object_handlers * default_object_handlers
Definition zend.h:186
zend_function * __callstatic
Definition zend.h:180
zend_object_get_debug_info_t get_debug_info
zend_object_read_property_t read_property
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
HashTable * properties
Definition zend_types.h:562
const zend_property_info * prototype
zend_function ** hooks
zend_string * name
zend_class_entry * ce
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
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_result zend_update_class_constants(zend_class_entry *class_type)
Definition zend_API.c:1518
ZEND_API const char * zend_get_type_by_const(int type)
Definition zend_API.c:112
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_none_error(void)
Definition zend_API.c:214
#define CE_STATIC_MEMBERS(ce)
Definition zend_API.h:328
#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 ZEND_FN(name)
Definition zend_API.h:71
#define ZEND_PARSE_PARAMETERS_END_EX(failure)
Definition zend_API.h:1630
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define ZEND_THIS
Definition zend_API.h:523
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define ZEND_FUNCTION(name)
Definition zend_API.h:75
#define RETVAL_COPY_VALUE(zv)
Definition zend_API.h:1029
#define RETVAL_COPY(zv)
Definition zend_API.h:1028
#define efree_size(ptr, size)
Definition zend_alloc.h:138
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define ALLOC_HASHTABLE(ht)
Definition zend_alloc.h:231
#define emalloc(size)
Definition zend_alloc.h:151
struct _zval_struct zval
strlen(string $string)
exit(string|int $status=0)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
execute_data func
zval * args
ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len)
#define BP_VAR_R
#define ZEND_ACC_NO_DYNAMIC_PROPERTIES
#define ZEND_USER_CODE(type)
#define IS_UNUSED
#define BP_VAR_W
#define ZEND_ACC_STRICT_TYPES
#define ZEND_INTERNAL_FUNCTION
#define ZEND_ACC_ABSTRACT
#define ZEND_ACC_READONLY
#define ZEND_ACC_PROTECTED_SET
#define ZEND_ACC_CHANGED
#define ZEND_ACC_PPP_SET_MASK
#define EX(element)
#define ZEND_USER_FUNCTION
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
struct _zend_op_array zend_op_array
#define OBJ_PROP(obj, offset)
struct _zend_property_info zend_property_info
#define ZEND_ACC_TRAIT
#define ZEND_ACC_USE_GUARDS
#define ZEND_ACC_PRIVATE
#define ZEND_ACC_CONSTANTS_UPDATED
#define ZEND_CALL_USES_STRICT_TYPES(call)
#define ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
#define ZEND_ACC_STATIC
#define ZEND_ACC_PUBLIC
struct _zend_arg_info zend_arg_info
#define EX_VAR(n)
#define ZEND_ACC_PUBLIC_SET
#define ZEND_ACC_VIRTUAL
#define ZEND_ACC_VARIADIC
#define IS_TMP_VAR
#define ZEND_DEBUGINFO_FUNC_NAME
#define BP_VAR_RW
#define ZEND_ACC_DEPRECATED
#define ZEND_ACC_RETURN_REFERENCE
char * zend_visibility_string(uint32_t fn_flags)
#define ZEND_FN_SCOPE_NAME(function)
#define ZEND_ACC_PROTECTED
#define BP_VAR_IS
#define BP_VAR_UNSET
#define ZEND_API
#define E_NOTICE
Definition zend_errors.h:26
#define E_ERROR
Definition zend_errors.h:23
#define E_WARNING
Definition zend_errors.h:24
#define E_DEPRECATED
Definition zend_errors.h:37
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_indirect_modification_error(const zend_property_info *info)
ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_info *info, zval *property, bool strict)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_object_released_while_assigning_to_property_error(const zend_property_info *info)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation)
ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(const zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context)
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(const zend_property_info *info)
#define CACHED_PTR_EX(slot)
#define ZEND_REF_HAS_TYPE_SOURCES(ref)
#define ZEND_REF_DEL_TYPE_SOURCE(ref, source)
ZEND_API zend_class_entry * zend_get_executed_scope(void)
ZEND_API void(* zend_execute_ex)(zend_execute_data *execute_data)
ZEND_API zend_object * zend_get_this_object(zend_execute_data *ex)
ZEND_API void execute_ex(zend_execute_data *execute_data)
#define CACHE_PTR_EX(slot, ptr)
#define CACHE_POLYMORPHIC_PTR_EX(slot, ce, ptr)
ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info)
@ ZEND_VERIFY_PROP_ASSIGNABLE_BY_REF_CONTEXT_MAGIC_GET
union _zend_function zend_function
#define EG(v)
ZEND_API zval *ZEND_FASTCALL zend_hash_add_new(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:1007
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API void ZEND_FASTCALL zend_hash_real_init_mixed(HashTable *ht)
Definition zend_hash.c:338
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_add(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:992
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define zend_new_array(size)
Definition zend_hash.h:338
#define HT_FLAGS(ht)
Definition zend_hash.h:50
#define HASH_FLAG_HAS_EMPTY_IND
Definition zend_hash.h:44
struct _zend_class_arrayaccess_funcs zend_class_arrayaccess_funcs
HashTable * zend_lazy_object_debug_info(zend_object *object, int *is_temp)
zend_object * zend_lazy_object_get_instance(zend_object *obj)
HashTable * zend_lazy_object_get_gc(zend_object *zobj, zval **table, int *n)
ZEND_API zend_object * zend_lazy_object_init(zend_object *obj)
struct _zend_string zend_string
#define ZEND_MAP_PTR_INIT(ptr, val)
#define ZEND_MAP_PTR_SET(ptr, val)
ZEND_API zval * zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *name, int type, void **cache_slot)
ZEND_API zval * zend_std_get_static_property_with_info(zend_class_entry *ce, zend_string *property_name, int type, zend_property_info **property_info_ptr)
#define ZEND_HOOKED_PROPERTY_OFFSET
ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic)
ZEND_API HashTable * zend_get_properties_for(zval *obj, zend_prop_purpose purpose)
#define IN_GET
ZEND_API zend_function * zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static)
#define IN_ISSET
ZEND_API HashTable * zend_std_get_debug_info(zend_object *object, int *is_temp)
ZEND_API HashTable * zend_get_properties_no_lazy_init(zend_object *zobj)
ZEND_API zend_string * zend_std_get_class_name(const zend_object *zobj)
ZEND_API void zend_class_init_statics(zend_class_entry *class_type)
#define ZEND_WRONG_PROPERTY_OFFSET
ZEND_API zend_function * zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key)
ZEND_API zend_result zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj, int type)
ZEND_API uint32_t * zend_get_recursion_guard(zend_object *zobj)
ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check_empty)
ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_entry *scope)
ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2)
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 ZEND_COLD bool zend_std_unset_static_property(zend_class_entry *ce, zend_string *property_name)
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 HashTable * zend_std_build_object_properties_array(zend_object *zobj)
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)
#define IN_UNSET
ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void **cache_slot)
ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset)
ZEND_API uint32_t * zend_get_property_guard(zend_object *zobj, zend_string *member)
ZEND_API zval * zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv)
ZEND_API zval * zend_std_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
ZEND_API int zend_std_compare_objects(zval *o1, zval *o2)
ZEND_API void zend_std_write_dimension(zend_object *object, zval *offset, zval *value)
#define IN_SET
ZEND_API zend_function * zend_get_property_hook_trampoline(const zend_property_info *prop_info, zend_property_hook_kind kind, zend_string *prop_name)
ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info)
ZEND_API HashTable * rebuild_object_properties_internal(zend_object *zobj)
ZEND_API HashTable * zend_std_get_gc(zend_object *zobj, zval **table, int *n)
ZEND_API zend_function * zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name, const zval *key)
ZEND_API zend_function * zend_std_get_constructor(zend_object *zobj)
ZEND_API zend_result zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only)
ZEND_API zval * zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, int type)
#define ZEND_WRONG_PROPERTY_INFO
#define IS_WRONG_PROPERTY_OFFSET(offset)
#define ZEND_SET_PROPERTY_HOOK_SIMPLE_WRITE(cache_slot)
#define ZEND_PROPERTY_ISSET
enum _zend_prop_purpose zend_prop_purpose
#define ZEND_DECODE_DYN_PROP_OFFSET(offset)
#define ZEND_SET_PROPERTY_HOOK_SIMPLE_READ(cache_slot)
#define ZEND_SET_PROPERTY_HOOK_SIMPLE_GET(cache_slot)
#define zend_get_function_root_class(fbc)
#define ZEND_ENCODE_DYN_PROP_OFFSET(offset)
#define IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(offset)
#define ZEND_PROPERTY_NOT_EMPTY
@ ZEND_PROP_PURPOSE_DEBUG
@ ZEND_PROP_PURPOSE_SERIALIZE
@ ZEND_PROP_PURPOSE_ARRAY_CAST
@ ZEND_PROP_PURPOSE_GET_OBJECT_VARS
@ ZEND_PROP_PURPOSE_VAR_EXPORT
@ ZEND_PROP_PURPOSE_JSON
#define IS_HOOKED_PROPERTY_OFFSET(offset)
#define ZEND_PROPERTY_EXISTS
#define ZEND_DYNAMIC_PROPERTY_OFFSET
#define IS_VALID_PROPERTY_OFFSET(offset)
#define zend_free_trampoline(func)
#define IS_DYNAMIC_PROPERTY_OFFSET(offset)
ZEND_API void zend_objects_destroy_object(zend_object *object)
ZEND_API zend_object * zend_objects_clone_obj(zend_object *old_object)
ZEND_API void zend_object_std_dtor(zend_object *object)
ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object)
#define OBJ_RELEASE(obj)
#define ZEND_OBSERVER_ENABLED
ZEND_API char *ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length)
ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2)
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_UNCOMPARABLE
#define ALLOCA_FLAG(name)
#define zend_never_inline
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_FASTCALL
#define ZEND_ASSERT(c)
#define ZEND_UNREACHABLE()
#define ZEND_COLD
#define UNEXPECTED(condition)
#define MAX(a, b)
ZEND_API zend_array * zend_hooked_object_build_properties(zend_object *zobj)
zend_property_hook_kind
@ ZEND_PROPERTY_HOOK_SET
@ ZEND_PROPERTY_HOOK_GET
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
ZEND_API zend_string * zend_string_concat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
#define ZSTR_ALLOCA_FREE(str, use_heap)
#define ZSTR_H(zstr)
Definition zend_string.h:70
#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 ZSTR_ALLOCA_ALLOC(str, _len, use_heap)
#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_UNDEF(z)
#define Z_REFVAL_P(zval_p)
#define IS_FALSE
Definition zend_types.h:602
#define ZEND_GUARD_PROPERTY_MASK
Definition zend_types.h:638
#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_TRUE(z)
#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)
#define ZVAL_INDIRECT(z, v)
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_OR_DUP(z, v)
#define IS_PROP_REINITABLE
#define Z_OBJ_HT_P(zval_p)
Definition zend_types.h:993
#define ZVAL_COPY_DEREF(z, v)
#define IS_DOUBLE
Definition zend_types.h:605
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
#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_FUNC_P(zval_p)
#define Z_REFVAL(zval)
#define GC_TRY_ADDREF(p)
Definition zend_types.h:713
#define Z_REFCOUNTED(zval)
Definition zend_types.h:917
#define Z_UNPROTECT_RECURSION_P(zv)
Definition zend_types.h:889
#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)
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
#define IS_REFERENCE
Definition zend_types.h:610
#define ZVAL_COPY(z, v)
#define Z_ARR(zval)
Definition zend_types.h:983
#define _IS_BOOL
Definition zend_types.h:629
struct _zend_refcounted zend_refcounted
Definition zend_types.h:95
struct _Bucket Bucket
#define Z_GUARD_P(zval_p)
Definition zend_types.h:690
#define Z_REF_P(zval_p)
#define ZVAL_DOUBLE(z, d)
#define Z_PROTECT_RECURSION_P(zv)
Definition zend_types.h:888
#define Z_REFCOUNT_P(pz)
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define IS_PROP_UNINIT
#define IS_ARRAY_IMMUTABLE
Definition zend_types.h:823
#define Z_REFCOUNT(z)
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define IS_PROP_LAZY
#define Z_PROP_FLAG_P(z)
#define GC_REFCOUNT(p)
Definition zend_types.h:707
#define Z_TYPE(zval)
Definition zend_types.h:659
#define IS_INDIRECT
Definition zend_types.h:623
#define Z_ARRVAL(zval)
Definition zend_types.h:986
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define ZVAL_COPY_VALUE(z, v)
#define ZVAL_DEINDIRECT(z)
#define Z_IS_RECURSIVE_P(zv)
Definition zend_types.h:887
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void ZEND_FASTCALL rc_dtor_func(zend_refcounted *p)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval retval
zend_property_info * prop_info
zend_string * name
zend_function * fbc
bool result
zval * variable_ptr
execute_data
object
zend_refcounted * garbage
zval * ret
value
new_op_array scope
zend_object * zobj
#define ZEND_FETCH_OBJ_R
#define ZEND_ASSIGN_OBJ