php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_inheritance.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 +----------------------------------------------------------------------+
18*/
19
20#include "zend.h"
21#include "zend_API.h"
22#include "zend_compile.h"
23#include "zend_execute.h"
24#include "zend_inheritance.h"
25#include "zend_interfaces.h"
26#include "zend_smart_str.h"
27#include "zend_operators.h"
28#include "zend_exceptions.h"
29#include "zend_enum.h"
30#include "zend_attributes.h"
31#include "zend_constants.h"
32#include "zend_observer.h"
33
34ZEND_API zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces) = NULL;
35ZEND_API zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies) = NULL;
36
37/* Unresolved means that class declarations that are currently not available are needed to
38 * determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
39 * as an ERROR. */
41
47
48static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
49static void add_compatibility_obligation(
50 zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
51 const zend_function *parent_fn, zend_class_entry *parent_scope);
52static void add_property_compatibility_obligation(
53 zend_class_entry *ce, const zend_property_info *child_prop,
54 const zend_property_info *parent_prop, prop_variance variance);
55static void add_class_constant_compatibility_obligation(
56 zend_class_entry *ce, const zend_class_constant *child_const,
57 const zend_class_constant *parent_const, const zend_string *const_name);
58static void add_property_hook_obligation(
59 zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func);
60
61static void ZEND_COLD emit_incompatible_method_error(
62 const zend_function *child, zend_class_entry *child_scope,
63 const zend_function *parent, zend_class_entry *parent_scope,
65
66static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent);
67
68static void zend_type_list_copy_ctor(
69 zend_type *const parent_type,
70 bool use_arena,
71 bool persistent
72) {
73 const zend_type_list *const old_list = ZEND_TYPE_LIST(*parent_type);
74 size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
75 zend_type_list *new_list = use_arena
76 ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
77
78 memcpy(new_list, old_list, size);
79 ZEND_TYPE_SET_LIST(*parent_type, new_list);
80 if (use_arena) {
82 }
83
84 zend_type *list_type;
85 ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
86 zend_type_copy_ctor(list_type, use_arena, persistent);
88}
89
90static void zend_type_copy_ctor(zend_type *const type, bool use_arena, bool persistent) {
92 zend_type_list_copy_ctor(type, use_arena, persistent);
93 } else if (ZEND_TYPE_HAS_NAME(*type)) {
94 zend_string_addref(ZEND_TYPE_NAME(*type));
95 }
96}
97
98static zend_function *zend_duplicate_internal_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
99{
100 zend_function *new_function;
101
103 new_function = (zend_function *)pemalloc(sizeof(zend_internal_function), 1);
104 memcpy(new_function, func, sizeof(zend_internal_function));
105 } else {
106 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
107 memcpy(new_function, func, sizeof(zend_internal_function));
109 }
110 if (EXPECTED(new_function->common.function_name)) {
111 zend_string_addref(new_function->common.function_name);
112 }
113 return new_function;
114}
115/* }}} */
116
117static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, const zend_class_entry *ce) /* {{{ */
118{
119 if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
120 return zend_duplicate_internal_function(func, ce);
121 } else {
122 if (func->op_array.refcount) {
123 (*func->op_array.refcount)++;
124 }
125 if (EXPECTED(func->op_array.function_name)) {
126 zend_string_addref(func->op_array.function_name);
127 }
128 return func;
129 }
130}
131/* }}} */
132
133static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
134{
135 zend_class_entry *parent = ce->parent;
136
137 ZEND_ASSERT(parent != NULL);
138
139 /* You cannot change create_object */
140 ce->create_object = parent->create_object;
141
142 /* Inherit special functions if needed */
143 if (EXPECTED(!ce->get_iterator)) {
144 ce->get_iterator = parent->get_iterator;
145 }
146 if (EXPECTED(!ce->__get)) {
147 ce->__get = parent->__get;
148 }
149 if (EXPECTED(!ce->__set)) {
150 ce->__set = parent->__set;
151 }
152 if (EXPECTED(!ce->__unset)) {
153 ce->__unset = parent->__unset;
154 }
155 if (EXPECTED(!ce->__isset)) {
156 ce->__isset = parent->__isset;
157 }
158 if (EXPECTED(!ce->__call)) {
159 ce->__call = parent->__call;
160 }
161 if (EXPECTED(!ce->__callstatic)) {
162 ce->__callstatic = parent->__callstatic;
163 }
164 if (EXPECTED(!ce->__tostring)) {
165 ce->__tostring = parent->__tostring;
166 }
167 if (EXPECTED(!ce->clone)) {
168 ce->clone = parent->clone;
169 }
170 if (EXPECTED(!ce->__serialize)) {
171 ce->__serialize = parent->__serialize;
172 }
173 if (EXPECTED(!ce->__unserialize)) {
174 ce->__unserialize = parent->__unserialize;
175 }
176 if (EXPECTED(!ce->serialize)) {
177 ce->serialize = parent->serialize;
178 }
179 if (EXPECTED(!ce->unserialize)) {
180 ce->unserialize = parent->unserialize;
181 }
182 if (!ce->destructor) {
183 ce->destructor = parent->destructor;
184 }
185 if (EXPECTED(!ce->__debugInfo)) {
186 ce->__debugInfo = parent->__debugInfo;
187 }
188
189 if (ce->constructor) {
190 if (parent->constructor && UNEXPECTED(parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
191 zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
192 ZSTR_VAL(parent->name), ZSTR_VAL(parent->constructor->common.function_name),
194 }
195 return;
196 }
197
198 ce->constructor = parent->constructor;
199}
200/* }}} */
201
202char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
203{
204 if (fn_flags & ZEND_ACC_PUBLIC) {
205 return "public";
206 } else if (fn_flags & ZEND_ACC_PRIVATE) {
207 return "private";
208 } else {
210 return "protected";
211 }
212}
213/* }}} */
214
215static const char *zend_asymmetric_visibility_string(uint32_t fn_flags) /* {{{ */
216{
217 if (fn_flags & ZEND_ACC_PRIVATE_SET) {
218 return "private(set)";
219 } else if (fn_flags & ZEND_ACC_PROTECTED_SET) {
220 return "protected(set)";
221 } else {
222 ZEND_ASSERT(!(fn_flags & ZEND_ACC_PUBLIC_SET));
223 return "omitted";
224 }
225}
226
227static zend_string *resolve_class_name(zend_class_entry *scope, zend_string *name) {
229 if (zend_string_equals_literal_ci(name, "parent") && scope->parent) {
230 if (scope->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
231 return scope->parent->name;
232 } else {
233 return scope->parent_name;
234 }
235 } else if (zend_string_equals_literal_ci(name, "self")) {
236 return scope->name;
237 } else {
238 return name;
239 }
240}
241
242static bool class_visible(const zend_class_entry *ce) {
243 if (ce->type == ZEND_INTERNAL_CLASS) {
244 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
245 } else {
247 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
248 || ce->info.user.filename == CG(compiled_filename);
249 }
250}
251
252static zend_always_inline void register_unresolved_class(zend_string *name) {
253 /* We'll autoload this class and process delayed variance obligations later. */
254 if (!CG(delayed_autoloads)) {
255 ALLOC_HASHTABLE(CG(delayed_autoloads));
256 zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
257 }
258 zend_hash_add_empty_element(CG(delayed_autoloads), name);
259}
260
261static zend_class_entry *lookup_class_ex(
262 zend_class_entry *scope, zend_string *name, bool register_unresolved) {
264 bool in_preload = CG(compiler_options) & ZEND_COMPILE_PRELOAD;
265
266 if (UNEXPECTED(!EG(active) && !in_preload)) {
267 zend_string *lc_name = zend_string_tolower(name);
268
269 ce = zend_hash_find_ptr(CG(class_table), lc_name);
270
271 zend_string_release(lc_name);
272
273 if (register_unresolved && !ce) {
275 E_COMPILE_ERROR, "%s must be registered before %s",
276 ZSTR_VAL(name), ZSTR_VAL(scope->name));
277 }
278
279 return ce;
280 }
281
284
285 if (!CG(in_compilation) || in_preload) {
286 if (ce) {
287 return ce;
288 }
289
290 if (register_unresolved) {
291 register_unresolved_class(name);
292 }
293 } else {
294 if (ce && class_visible(ce)) {
295 return ce;
296 }
297
298 /* The current class may not be registered yet, so check for it explicitly. */
299 if (zend_string_equals_ci(scope->name, name)) {
300 return scope;
301 }
302 }
303
304 return NULL;
305}
306
307static zend_class_entry *lookup_class(zend_class_entry *scope, zend_string *name) {
308 return lookup_class_ex(scope, name, /* register_unresolved */ false);
309}
310
311/* Instanceof that's safe to use on unlinked classes. */
312static bool unlinked_instanceof(zend_class_entry *ce1, const zend_class_entry *ce2) {
313 if (ce1 == ce2) {
314 return 1;
315 }
316
317 if (ce1->ce_flags & ZEND_ACC_LINKED) {
318 return instanceof_function(ce1, ce2);
319 }
320
321 if (ce1->parent) {
322 zend_class_entry *parent_ce;
324 parent_ce = ce1->parent;
325 } else {
326 parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
328 }
329
330 /* It's not sufficient to only check the parent chain itself, as need to do a full
331 * recursive instanceof in case the parent interfaces haven't been copied yet. */
332 if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
333 return 1;
334 }
335 }
336
337 if (ce1->num_interfaces) {
338 uint32_t i;
340 /* Unlike the normal instanceof_function(), we have to perform a recursive
341 * check here, as the parent interfaces might not have been fully copied yet. */
342 for (i = 0; i < ce1->num_interfaces; i++) {
343 if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
344 return 1;
345 }
346 }
347 } else {
348 for (i = 0; i < ce1->num_interfaces; i++) {
352 /* Avoid recursing if class implements itself. */
353 if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
354 return 1;
355 }
356 }
357 }
358 }
359
360 return 0;
361}
362
363static bool zend_type_permits_self(
366 return 1;
367 }
368
369 /* Any types that may satisfy self must have already been loaded at this point
370 * (as a parent or interface), so we never need to register delayed variance obligations
371 * for this case. */
372 zend_type *single_type;
373 ZEND_TYPE_FOREACH(type, single_type) {
374 if (ZEND_TYPE_HAS_NAME(*single_type)) {
375 zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
376 zend_class_entry *ce = lookup_class(self, name);
377 if (ce && unlinked_instanceof(self, ce)) {
378 return 1;
379 }
380 }
382 return 0;
383}
384
385static void track_class_dependency(zend_class_entry *ce, zend_string *class_name)
386{
387 HashTable *ht;
388
389 ZEND_ASSERT(class_name);
390 if (!CG(current_linking_class) || ce == CG(current_linking_class)) {
391 return;
392 } else if (zend_string_equals_literal_ci(class_name, "self")
393 || zend_string_equals_literal_ci(class_name, "parent")) {
394 return;
395 }
396
397#ifndef ZEND_WIN32
398 /* On non-Windows systems, internal classes are always the same,
399 * so there is no need to explicitly track them. */
400 if (ce->type == ZEND_INTERNAL_CLASS) {
401 return;
402 }
403#endif
404
405 ht = (HashTable*)CG(current_linking_class)->inheritance_cache;
406
407 if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
408 // TODO: dependency on not-immutable class ???
409 if (ht) {
412 CG(current_linking_class)->inheritance_cache = NULL;
413 }
414 CG(current_linking_class)->ce_flags &= ~ZEND_ACC_CACHEABLE;
415 CG(current_linking_class) = NULL;
416 return;
417 }
418
419 /* Record dependency */
420 if (!ht) {
422 zend_hash_init(ht, 0, NULL, NULL, 0);
423 CG(current_linking_class)->inheritance_cache = (zend_inheritance_cache_entry*)ht;
424 }
425 zend_hash_add_ptr(ht, class_name, ce);
426}
427
428/* Check whether any type in the fe_type intersection type is a subtype of the proto class. */
429static inheritance_status zend_is_intersection_subtype_of_class(
430 zend_class_entry *fe_scope, zend_type fe_type,
431 zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce)
432{
434 bool have_unresolved = false;
435 zend_type *single_type;
436
437 /* Traverse the list of child types and check that at least one is
438 * a subtype of the parent type being checked */
439 ZEND_TYPE_FOREACH(fe_type, single_type) {
440 zend_class_entry *fe_ce;
441 zend_string *fe_class_name = NULL;
442 if (ZEND_TYPE_HAS_NAME(*single_type)) {
443 fe_class_name =
444 resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
445 if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
446 return INHERITANCE_SUCCESS;
447 }
448
449 if (!proto_ce) proto_ce = lookup_class(proto_scope, proto_class_name);
450 fe_ce = lookup_class(fe_scope, fe_class_name);
451 } else {
452 /* standard type in an intersection type is impossible,
453 * because it would be a fatal compile error */
455 continue;
456 }
457
458 if (!fe_ce || !proto_ce) {
459 have_unresolved = true;
460 continue;
461 }
462 if (unlinked_instanceof(fe_ce, proto_ce)) {
463 track_class_dependency(fe_ce, fe_class_name);
464 track_class_dependency(proto_ce, proto_class_name);
465 return INHERITANCE_SUCCESS;
466 }
468
469 return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
470}
471
472/* Check whether a single class proto type is a subtype of a potentially complex fe_type. */
473static inheritance_status zend_is_class_subtype_of_type(
474 zend_class_entry *fe_scope, zend_string *fe_class_name,
475 zend_class_entry *proto_scope, zend_type proto_type) {
476 zend_class_entry *fe_ce = NULL;
477 bool have_unresolved = 0;
478
479 /* If the parent has 'object' as a return type, any class satisfies the co-variant check */
480 if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) {
481 /* Currently, any class name would be allowed here. We still perform a class lookup
482 * for forward-compatibility reasons, as we may have named types in the future that
483 * are not classes (such as typedefs). */
484 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
485 if (!fe_ce) {
486 have_unresolved = 1;
487 } else {
488 track_class_dependency(fe_ce, fe_class_name);
489 return INHERITANCE_SUCCESS;
490 }
491 }
492
493 zend_type *single_type;
494
495 /* Traverse the list of parent types and check if the current child (FE)
496 * class is the subtype of at least one of them (union) or all of them (intersection). */
497 bool is_intersection = ZEND_TYPE_IS_INTERSECTION(proto_type);
498 ZEND_TYPE_FOREACH(proto_type, single_type) {
499 if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
500 inheritance_status subtype_status = zend_is_class_subtype_of_type(
501 fe_scope, fe_class_name, proto_scope, *single_type);
502
503 switch (subtype_status) {
505 if (is_intersection) {
506 return INHERITANCE_ERROR;
507 }
508 continue;
510 have_unresolved = 1;
511 continue;
513 if (!is_intersection) {
514 return INHERITANCE_SUCCESS;
515 }
516 continue;
518 }
519 }
520
521 zend_class_entry *proto_ce;
522 zend_string *proto_class_name = NULL;
523 if (ZEND_TYPE_HAS_NAME(*single_type)) {
524 proto_class_name =
525 resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
526 if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
527 if (!is_intersection) {
528 return INHERITANCE_SUCCESS;
529 }
530 continue;
531 }
532
533 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name);
534 proto_ce = lookup_class(proto_scope, proto_class_name);
535 } else {
536 /* standard type */
537 ZEND_ASSERT(!is_intersection);
538 continue;
539 }
540
541 if (!fe_ce || !proto_ce) {
542 have_unresolved = 1;
543 continue;
544 }
545 if (unlinked_instanceof(fe_ce, proto_ce)) {
546 track_class_dependency(fe_ce, fe_class_name);
547 track_class_dependency(proto_ce, proto_class_name);
548 if (!is_intersection) {
549 return INHERITANCE_SUCCESS;
550 }
551 } else {
552 if (is_intersection) {
553 return INHERITANCE_ERROR;
554 }
555 }
557
558 if (have_unresolved) {
560 }
561 return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
562}
563
564static zend_string *get_class_from_type(zend_class_entry *scope, zend_type single_type) {
565 if (ZEND_TYPE_HAS_NAME(single_type)) {
566 return resolve_class_name(scope, ZEND_TYPE_NAME(single_type));
567 }
568 return NULL;
569}
570
571static void register_unresolved_classes(zend_class_entry *scope, zend_type type) {
572 zend_type *single_type;
573 ZEND_TYPE_FOREACH(type, single_type) {
574 if (ZEND_TYPE_HAS_LIST(*single_type)) {
575 register_unresolved_classes(scope, *single_type);
576 continue;
577 }
578 if (ZEND_TYPE_HAS_NAME(*single_type)) {
579 zend_string *class_name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
580 lookup_class_ex(scope, class_name, /* register_unresolved */ true);
581 }
583}
584
585static inheritance_status zend_is_intersection_subtype_of_type(
586 zend_class_entry *fe_scope, zend_type fe_type,
587 zend_class_entry *proto_scope, zend_type proto_type)
588{
589 bool have_unresolved = false;
590 zend_type *single_type;
591 uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
592
593 /* Currently, for object type any class name would be allowed here.
594 * We still perform a class lookup for forward-compatibility reasons,
595 * as we may have named types in the future that are not classes
596 * (such as typedefs). */
597 if (proto_type_mask & MAY_BE_OBJECT) {
598 ZEND_TYPE_FOREACH(fe_type, single_type) {
599 zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
600 if (!fe_class_name) {
601 continue;
602 }
603 zend_class_entry *fe_ce = lookup_class(fe_scope, fe_class_name);
604 if (fe_ce) {
605 track_class_dependency(fe_ce, fe_class_name);
606 return INHERITANCE_SUCCESS;
607 } else {
608 have_unresolved = true;
609 }
611 }
612
613 /* U_1&...&U_n < V_1&...&V_m if forall V_j. exists U_i. U_i < V_j.
614 * U_1&...&U_n < V_1|...|V_m if exists V_j. exists U_i. U_i < V_j.
615 * As such, we need to iterate over proto_type (V_j) first and use a different
616 * quantifier depending on whether fe_type is a union or an intersection. */
617 inheritance_status early_exit_status =
619 ZEND_TYPE_FOREACH(proto_type, single_type) {
621
622 if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
623 status = zend_is_intersection_subtype_of_type(
624 fe_scope, fe_type, proto_scope, *single_type);
625 } else {
626 zend_string *proto_class_name = get_class_from_type(proto_scope, *single_type);
627 if (!proto_class_name) {
628 continue;
629 }
630
631 zend_class_entry *proto_ce = NULL;
632 status = zend_is_intersection_subtype_of_class(
633 fe_scope, fe_type, proto_scope, proto_class_name, proto_ce);
634 }
635
636 if (status == early_exit_status) {
637 return status;
638 }
640 have_unresolved = true;
641 }
643
644 if (have_unresolved) {
646 }
647
648 return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
649}
650
652 zend_class_entry *fe_scope, zend_type fe_type,
653 zend_class_entry *proto_scope, zend_type proto_type)
654{
655 ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_type) && ZEND_TYPE_IS_SET(proto_type));
656
657 /* Apart from void, everything is trivially covariant to the mixed type.
658 * Handle this case separately to ensure it never requires class loading. */
659 if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
660 !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
661 return INHERITANCE_SUCCESS;
662 }
663
664 /* Builtin types may be removed, but not added */
665 uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
666 uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
667 uint32_t added_types = fe_type_mask & ~proto_type_mask;
668 if (added_types) {
669 if ((added_types & MAY_BE_STATIC)
670 && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
671 /* Replacing type that accepts self with static is okay */
672 added_types &= ~MAY_BE_STATIC;
673 }
674
675 if (added_types == MAY_BE_NEVER) {
676 /* never is the bottom type */
677 return INHERITANCE_SUCCESS;
678 }
679
680 if (added_types) {
681 /* Otherwise adding new types is illegal */
682 return INHERITANCE_ERROR;
683 }
684 }
685
686 zend_type *single_type;
687 inheritance_status early_exit_status;
688 bool have_unresolved = false;
689
690 if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
691 early_exit_status =
693 inheritance_status status = zend_is_intersection_subtype_of_type(
694 fe_scope, fe_type, proto_scope, proto_type);
695
696 if (status == early_exit_status) {
697 return status;
698 }
700 have_unresolved = true;
701 }
702 } else {
703 /* U_1|...|U_n < V_1|...|V_m if forall U_i. exists V_j. U_i < V_j.
704 * U_1|...|U_n < V_1&...&V_m if forall U_i. forall V_j. U_i < V_j.
705 * We need to iterate over fe_type (U_i) first and the logic is independent of
706 * whether proto_type is a union or intersection (only the inner check differs). */
707 early_exit_status = INHERITANCE_ERROR;
708 ZEND_TYPE_FOREACH(fe_type, single_type) {
710 /* Union has an intersection type as it's member */
711 if (ZEND_TYPE_IS_INTERSECTION(*single_type)) {
712 status = zend_is_intersection_subtype_of_type(
713 fe_scope, *single_type, proto_scope, proto_type);
714 } else {
715 zend_string *fe_class_name = get_class_from_type(fe_scope, *single_type);
716 if (!fe_class_name) {
717 continue;
718 }
719
720 status = zend_is_class_subtype_of_type(
721 fe_scope, fe_class_name, proto_scope, proto_type);
722 }
723
724 if (status == early_exit_status) {
725 return status;
726 }
728 have_unresolved = true;
729 }
731 }
732
733 if (!have_unresolved) {
734 return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
735 }
736
737 register_unresolved_classes(fe_scope, fe_type);
738 register_unresolved_classes(proto_scope, proto_type);
740}
741
742static inheritance_status zend_do_perform_arg_type_hint_check(
743 zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
744 zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
745{
746 if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
747 /* Child with no type or mixed type is always compatible */
748 return INHERITANCE_SUCCESS;
749 }
750
751 if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
752 /* Child defines a type, but parent doesn't, violates LSP */
753 return INHERITANCE_ERROR;
754 }
755
756 /* Contravariant type check is performed as a covariant type check with swapped
757 * argument order. */
759 proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
760}
761/* }}} */
762
763/* For trait methods, fe_scope/proto_scope may differ from fe/proto->common.scope,
764 * as self will refer to the self of the class the trait is used in, not the trait
765 * the method was declared in. */
766static inheritance_status zend_do_perform_implementation_check(
767 const zend_function *fe, zend_class_entry *fe_scope,
768 const zend_function *proto, zend_class_entry *proto_scope) /* {{{ */
769{
770 uint32_t i, num_args, proto_num_args, fe_num_args;
771 inheritance_status status, local_status;
772 bool proto_is_variadic, fe_is_variadic;
773
774 /* Checks for constructors only if they are declared in an interface,
775 * or explicitly marked as abstract
776 */
778 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
779 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)));
780
781 /* If the prototype method is private and not abstract, we do not enforce a signature.
782 * private abstract methods can only occur in traits. */
784 || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
785
786 /* The number of required arguments cannot increase. */
788 return INHERITANCE_ERROR;
789 }
790
791 /* by-ref constraints on return values are covariant */
794 return INHERITANCE_ERROR;
795 }
796
797 proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
798 fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
799
800 /* A variadic function cannot become non-variadic */
801 if (proto_is_variadic && !fe_is_variadic) {
802 return INHERITANCE_ERROR;
803 }
804
805 /* The variadic argument is not included in the stored argument count. */
806 proto_num_args = proto->common.num_args + proto_is_variadic;
807 fe_num_args = fe->common.num_args + fe_is_variadic;
808 num_args = MAX(proto_num_args, fe_num_args);
809
811 for (i = 0; i < num_args; i++) {
812 zend_arg_info *proto_arg_info =
813 i < proto_num_args ? &proto->common.arg_info[i] :
814 proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
815 zend_arg_info *fe_arg_info =
816 i < fe_num_args ? &fe->common.arg_info[i] :
817 fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
818 if (!proto_arg_info) {
819 /* A new (optional) argument has been added, which is fine. */
820 continue;
821 }
822 if (!fe_arg_info) {
823 /* An argument has been removed. This is considered illegal, because arity checks
824 * work based on a model where passing more than the declared number of parameters
825 * to a function is an error. */
826 return INHERITANCE_ERROR;
827 }
828
829 local_status = zend_do_perform_arg_type_hint_check(
830 fe_scope, fe_arg_info, proto_scope, proto_arg_info);
831
832 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
833 if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
834 return INHERITANCE_ERROR;
835 }
836 ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
838 }
839
840 /* by-ref constraints on arguments are invariant */
841 if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
842 return INHERITANCE_ERROR;
843 }
844 }
845
846 /* Check return type compatibility, but only if the prototype already specifies
847 * a return type. Adding a new return type is always valid. */
849 /* Removing a return type is not valid, unless the parent return type is tentative. */
851 if (!ZEND_ARG_TYPE_IS_TENTATIVE(&proto->common.arg_info[-1])) {
852 return INHERITANCE_ERROR;
853 }
855 return INHERITANCE_WARNING;
856 }
857 return status;
858 }
859
861 fe_scope, fe->common.arg_info[-1].type, proto_scope, proto->common.arg_info[-1].type);
862
863 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
864 if (local_status == INHERITANCE_ERROR
866 local_status = INHERITANCE_WARNING;
867 }
868 return local_status;
869 }
870 }
871
872 return status;
873}
874/* }}} */
875
876static ZEND_COLD void zend_append_type_hint(
877 smart_str *str, zend_class_entry *scope, const zend_arg_info *arg_info, bool return_hint) /* {{{ */
878{
879 if (ZEND_TYPE_IS_SET(arg_info->type)) {
880 zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
881 smart_str_append(str, type_str);
882 zend_string_release(type_str);
883 if (!return_hint) {
884 smart_str_appendc(str, ' ');
885 }
886 }
887}
888/* }}} */
889
890static ZEND_COLD zend_string *zend_get_function_declaration(
891 const zend_function *fptr, zend_class_entry *scope) /* {{{ */
892{
893 smart_str str = {0};
894
896 smart_str_appends(&str, "& ");
897 }
898
899 if (fptr->common.scope) {
901 /* cut off on NULL byte ... class@anonymous */
902 smart_str_appends(&str, ZSTR_VAL(fptr->common.scope->name));
903 } else {
904 smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), ZSTR_LEN(fptr->common.scope->name));
905 }
906 smart_str_appends(&str, "::");
907 }
908
909 smart_str_append(&str, fptr->common.function_name);
910 smart_str_appendc(&str, '(');
911
912 if (fptr->common.arg_info) {
913 uint32_t i, num_args, required;
914 zend_arg_info *arg_info = fptr->common.arg_info;
915
916 required = fptr->common.required_num_args;
917 num_args = fptr->common.num_args;
918 if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
919 num_args++;
920 }
921 for (i = 0; i < num_args;) {
922 zend_append_type_hint(&str, scope, arg_info, 0);
923
924 if (ZEND_ARG_SEND_MODE(arg_info)) {
925 smart_str_appendc(&str, '&');
926 }
927
928 if (ZEND_ARG_IS_VARIADIC(arg_info)) {
929 smart_str_appends(&str, "...");
930 }
931
932 smart_str_appendc(&str, '$');
933 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
934 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
935 } else {
936 smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
937 }
938
939 if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
940 smart_str_appends(&str, " = ");
941
942 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
943 if (((zend_internal_arg_info*)arg_info)->default_value) {
944 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value);
945 } else {
946 smart_str_appends(&str, "<default>");
947 }
948 } else {
949 zend_op *precv = NULL;
950 {
951 uint32_t idx = i;
952 zend_op *op = fptr->op_array.opcodes;
953 zend_op *end = op + fptr->op_array.last;
954
955 ++idx;
956 while (op < end) {
957 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
958 && op->op1.num == (zend_ulong)idx)
959 {
960 precv = op;
961 }
962 ++op;
963 }
964 }
965 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
966 zval *zv = RT_CONSTANT(precv, precv->op2);
967
968 if (Z_TYPE_P(zv) == IS_FALSE) {
969 smart_str_appends(&str, "false");
970 } else if (Z_TYPE_P(zv) == IS_TRUE) {
971 smart_str_appends(&str, "true");
972 } else if (Z_TYPE_P(zv) == IS_NULL) {
973 smart_str_appends(&str, "null");
974 } else if (Z_TYPE_P(zv) == IS_STRING) {
975 smart_str_appendc(&str, '\'');
976 smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
977 if (Z_STRLEN_P(zv) > 10) {
978 smart_str_appends(&str, "...");
979 }
980 smart_str_appendc(&str, '\'');
981 } else if (Z_TYPE_P(zv) == IS_ARRAY) {
982 if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
983 smart_str_appends(&str, "[]");
984 } else {
985 smart_str_appends(&str, "[...]");
986 }
987 } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
988 zend_ast *ast = Z_ASTVAL_P(zv);
989 if (ast->kind == ZEND_AST_CONSTANT) {
990 smart_str_append(&str, zend_ast_get_constant_name(ast));
991 } else if (ast->kind == ZEND_AST_CLASS_CONST) {
992 smart_str_append(&str, zend_ast_get_str(ast->child[0]));
993 smart_str_appends(&str, "::");
994 smart_str_append(&str, zend_ast_get_str(ast->child[1]));
995 } else {
996 smart_str_appends(&str, "<expression>");
997 }
998 } else {
999 zend_string *tmp_zv_str;
1000 zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
1001 smart_str_append(&str, zv_str);
1002 zend_tmp_string_release(tmp_zv_str);
1003 }
1004 }
1005 }
1006 }
1007
1008 if (++i < num_args) {
1009 smart_str_appends(&str, ", ");
1010 }
1011 arg_info++;
1012 }
1013 }
1014
1015 smart_str_appendc(&str, ')');
1016
1018 smart_str_appends(&str, ": ");
1019 zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, 1);
1020 }
1021 smart_str_0(&str);
1022
1023 return str.s;
1024}
1025/* }}} */
1026
1027static zend_always_inline zend_string *func_filename(const zend_function *fn) {
1028 return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.filename : NULL;
1029}
1030
1031static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
1032 return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
1033}
1034
1035static void ZEND_COLD emit_incompatible_method_error(
1036 const zend_function *child, zend_class_entry *child_scope,
1037 const zend_function *parent, zend_class_entry *parent_scope,
1039 zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
1040 zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
1042 // TODO Improve error message if first unresolved class is present in child and parent?
1043 /* Fetch the first unresolved class from registered autoloads */
1044 const zend_string *unresolved_class = NULL;
1045 ZEND_HASH_MAP_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
1046 break;
1048 ZEND_ASSERT(unresolved_class);
1049
1050 zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1051 "Could not check compatibility between %s and %s, because class %s is not available",
1052 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
1053 } else if (status == INHERITANCE_WARNING) {
1054 const zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
1055 child->common.attributes,
1056 "returntypewillchange",
1057 sizeof("returntypewillchange")-1
1058 );
1059
1060 if (!return_type_will_change_attribute) {
1061 zend_error_at(E_DEPRECATED, func_filename(child), func_lineno(child),
1062 "Return type of %s should either be compatible with %s, "
1063 "or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
1064 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1065 if (EG(exception)) {
1067 "During inheritance of %s", ZSTR_VAL(parent_scope->name));
1068 }
1069 }
1070 } else {
1071 zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1072 "Declaration of %s must be compatible with %s",
1073 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
1074 }
1075 zend_string_efree(child_prototype);
1076 zend_string_efree(parent_prototype);
1077}
1078
1079static void perform_delayable_implementation_check(
1080 zend_class_entry *ce,
1081 const zend_function *fe, zend_class_entry *fe_scope,
1082 const zend_function *proto, zend_class_entry *proto_scope)
1083{
1085 zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
1088 add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
1089 } else {
1091 emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
1092 }
1093 }
1094}
1095
1096#define ZEND_INHERITANCE_LAZY_CHILD_CLONE (1<<0)
1097#define ZEND_INHERITANCE_CHECK_SILENT (1<<1) /* don't throw errors */
1098#define ZEND_INHERITANCE_CHECK_PROTO (1<<2) /* check method prototype (it might be already checked before) */
1099#define ZEND_INHERITANCE_CHECK_VISIBILITY (1<<3)
1100#define ZEND_INHERITANCE_SET_CHILD_CHANGED (1<<4)
1101#define ZEND_INHERITANCE_SET_CHILD_PROTO (1<<5)
1102#define ZEND_INHERITANCE_RESET_CHILD_OVERRIDE (1<<6)
1103
1104static inheritance_status do_inheritance_check_on_method(
1105 zend_function *child, zend_class_entry *child_scope,
1106 zend_function *parent, zend_class_entry *parent_scope,
1107 zend_class_entry *ce, zval *child_zv, uint32_t flags) /* {{{ */
1108{
1109 uint32_t child_flags;
1110 uint32_t parent_flags = parent->common.fn_flags;
1111 zend_function *proto;
1112
1113#define SEPARATE_METHOD() do { \
1114 if ((flags & ZEND_INHERITANCE_LAZY_CHILD_CLONE) \
1115 && child_scope != ce && child->type == ZEND_USER_FUNCTION) { \
1116 /* op_array wasn't duplicated yet */ \
1117 zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); \
1118 memcpy(new_function, child, sizeof(zend_op_array)); \
1119 Z_PTR_P(child_zv) = child = new_function; \
1120 flags &= ~ZEND_INHERITANCE_LAZY_CHILD_CLONE; \
1121 } \
1122 } while(0)
1123
1128 }
1129 /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
1130 return INHERITANCE_SUCCESS;
1131 }
1132
1133 if ((flags & ZEND_INHERITANCE_CHECK_PROTO) && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
1135 return INHERITANCE_ERROR;
1136 }
1137 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1138 "Cannot override final method %s::%s()",
1140 }
1141
1142 child_flags = child->common.fn_flags;
1143 /* You cannot change from static to non static and vice versa.
1144 */
1146 && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
1148 return INHERITANCE_ERROR;
1149 }
1150 if (child_flags & ZEND_ACC_STATIC) {
1151 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1152 "Cannot make non static method %s::%s() static in class %s",
1154 } else {
1155 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1156 "Cannot make static method %s::%s() non static in class %s",
1158 }
1159 }
1160
1161 /* Disallow making an inherited method abstract. */
1163 && UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
1165 return INHERITANCE_ERROR;
1166 }
1167 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1168 "Cannot make non abstract method %s::%s() abstract in class %s",
1170 }
1171
1173 && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
1176 }
1177
1178 proto = parent->common.prototype ?
1179 parent->common.prototype : parent;
1180
1181 if (parent_flags & ZEND_ACC_CTOR) {
1182 /* ctors only have a prototype if is abstract (or comes from an interface) */
1183 /* and if that is the case, we want to check inheritance against it */
1184 if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
1185 return INHERITANCE_SUCCESS;
1186 }
1187 parent = proto;
1188 }
1189
1191 && child->common.prototype != proto) {
1193 child->common.prototype = proto;
1194 }
1195
1196 /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
1198 && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
1200 return INHERITANCE_ERROR;
1201 }
1202 zend_error_at_noreturn(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
1203 "Access level to %s::%s() must be %s (as in class %s)%s",
1204 ZEND_FN_SCOPE_NAME(child), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1205 }
1206
1209 return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
1210 }
1211 perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
1212 }
1213
1215 && (child->common.fn_flags & ZEND_ACC_OVERRIDE)) {
1218 }
1219
1220#undef SEPARATE_METHOD
1221
1222 return INHERITANCE_SUCCESS;
1223}
1224/* }}} */
1225
1226static void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, bool is_interface, uint32_t flags) /* {{{ */
1227{
1229
1230 if (child) {
1232
1233 if (is_interface && UNEXPECTED(func == parent)) {
1234 /* The same method in interface may be inherited few times */
1235 return;
1236 }
1237
1238 do_inheritance_check_on_method(
1239 func, func->common.scope, parent, parent->common.scope, ce, child, flags);
1240 } else {
1241
1242 if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
1244 }
1245
1246 parent = zend_duplicate_function(parent, ce);
1247
1248 if (!is_interface) {
1249 _zend_hash_append_ptr(&ce->function_table, key, parent);
1250 } else {
1251 zend_hash_add_new_ptr(&ce->function_table, key, parent);
1252 }
1253 }
1254}
1255/* }}} */
1256
1257static inheritance_status full_property_types_compatible(
1258 const zend_property_info *parent_info, const zend_property_info *child_info,
1259 prop_variance variance) {
1260 if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
1261 && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1262 return INHERITANCE_SUCCESS;
1263 }
1264
1265 if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1266 return INHERITANCE_ERROR;
1267 }
1268
1269 /* Perform a covariant type check in both directions to determined invariance. */
1272 child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1273 inheritance_status status2 = variance == PROP_COVARIANT ? INHERITANCE_SUCCESS :
1275 parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1276 if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1277 return INHERITANCE_SUCCESS;
1278 }
1279 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1280 return INHERITANCE_ERROR;
1281 }
1284}
1285
1286static ZEND_COLD void emit_incompatible_property_error(
1287 const zend_property_info *child, const zend_property_info *parent, prop_variance variance) {
1288 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1290 "Type of %s::$%s must be %s%s (as in class %s)",
1291 ZSTR_VAL(child->ce->name),
1292 zend_get_unmangled_property_name(child->name),
1293 variance == PROP_INVARIANT ? "" :
1294 variance == PROP_COVARIANT ? "subtype of " : "supertype of ",
1295 ZSTR_VAL(type_str),
1296 ZSTR_VAL(parent->ce->name));
1297}
1298
1299static ZEND_COLD void emit_set_hook_type_error(const zend_property_info *child, const zend_property_info *parent)
1300{
1301 zend_type set_type = parent->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1302 zend_string *type_str = zend_type_to_string_resolved(set_type, parent->ce);
1304 "Set type of %s::$%s must be supertype of %s (as in %s %s)",
1305 ZSTR_VAL(child->ce->name),
1306 zend_get_unmangled_property_name(child->name),
1307 ZSTR_VAL(type_str),
1308 zend_get_object_type_case(parent->ce, false),
1309 ZSTR_VAL(parent->ce->name));
1310}
1311
1312static inheritance_status verify_property_type_compatibility(
1313 const zend_property_info *parent_info,
1314 const zend_property_info *child_info,
1315 prop_variance variance,
1316 bool throw_on_error,
1317 bool throw_on_unresolved
1318) {
1319 inheritance_status result = full_property_types_compatible(parent_info, child_info, variance);
1320 if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1321 emit_incompatible_property_error(child_info, parent_info, variance);
1322 }
1323 if (result != INHERITANCE_SUCCESS) {
1324 return result;
1325 }
1326 if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1327 ZEND_ASSERT(parent_info->hooks);
1328 if (parent_info->hooks[ZEND_PROPERTY_HOOK_SET]
1329 && (!child_info->hooks || !child_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1330 zend_type set_type = parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0].type;
1332 parent_info->ce, set_type, child_info->ce, child_info->type);
1333 if ((result == INHERITANCE_ERROR && throw_on_error) || (result == INHERITANCE_UNRESOLVED && throw_on_unresolved)) {
1334 emit_set_hook_type_error(child_info, parent_info);
1335 }
1336 }
1337 }
1338 return INHERITANCE_SUCCESS;
1339}
1340
1341static bool property_has_operation(zend_property_info *prop_info, zend_property_hook_kind kind)
1342{
1343 return (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1345 || (prop_info->hooks && prop_info->hooks[kind]);
1346}
1347
1348static void inherit_property_hook(
1349 zend_class_entry *ce,
1350 zend_property_info *parent_info,
1351 zend_property_info *child_info,
1353) {
1354 zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
1355 zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;
1356
1357 if (child
1358 && (child->common.fn_flags & ZEND_ACC_OVERRIDE)
1359 && property_has_operation(parent_info, kind)) {
1361 }
1362
1363 if (!parent) {
1364 return;
1365 }
1366
1367 if (!child) {
1368 if (parent->common.fn_flags & ZEND_ACC_ABSTRACT) {
1369 /* Backed properties are considered to always implement get, and set when they are not readonly. */
1370 if (property_has_operation(child_info, kind)) {
1371 return;
1372 }
1374 }
1375 if (!child_info->hooks) {
1376 ce->num_hooked_props++;
1377 child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
1379 }
1380 child_info->hooks[kind] = zend_duplicate_function(parent, ce);
1381 return;
1382 }
1383
1384 child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
1385
1386 uint32_t parent_flags = parent->common.fn_flags;
1387 if (parent_flags & ZEND_ACC_PRIVATE) {
1389 return;
1390 }
1391
1392 if (parent_flags & ZEND_ACC_FINAL) {
1394 "Cannot override final property hook %s::%s()",
1395 ZSTR_VAL(parent->common.scope->name),
1396 ZSTR_VAL(parent->common.function_name));
1397 }
1398
1399 do_inheritance_check_on_method(
1400 child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
1404
1405 /* Other signature compatibility issues should already be covered either by the
1406 * properties being compatible (types), or certain signatures being forbidden by the
1407 * compiler (variadic and by-ref args, etc). */
1408}
1409
1410static prop_variance prop_get_variance(const zend_property_info *prop_info) {
1411 bool unbacked = prop_info->flags & ZEND_ACC_VIRTUAL;
1412 if (unbacked && prop_info->hooks) {
1413 if (!prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1414 return PROP_COVARIANT;
1415 }
1416 if (!prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
1417 return PROP_CONTRAVARIANT;
1418 }
1419 }
1420 return PROP_INVARIANT;
1421}
1422
1423static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1424{
1426 zend_property_info *child_info;
1427
1428 if (UNEXPECTED(child)) {
1429 child_info = Z_PTR_P(child);
1430 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1431 child_info->flags |= ZEND_ACC_CHANGED;
1432 }
1433 if (parent_info->flags & ZEND_ACC_FINAL) {
1434 zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final property %s::$%s",
1435 ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key));
1436 }
1437 if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1438 if (!(parent_info->ce->ce_flags & ZEND_ACC_INTERFACE)) {
1439 child_info->prototype = parent_info->prototype;
1440 }
1441
1442 if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1443 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1444 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1445 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1446 }
1447 if (UNEXPECTED((child_info->flags & ZEND_ACC_READONLY) != (parent_info->flags & ZEND_ACC_READONLY))) {
1448 if (!(parent_info->flags & ZEND_ACC_ABSTRACT)) {
1450 "Cannot redeclare %s property %s::$%s as %s %s::$%s",
1451 parent_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1452 ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1453 child_info->flags & ZEND_ACC_READONLY ? "readonly" : "non-readonly",
1454 ZSTR_VAL(ce->name), ZSTR_VAL(key));
1455 }
1456 }
1457 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_SET_MASK))
1458 /* Get-only virtual properties have no set visibility, so any child visibility is fine. */
1459 && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {
1460 uint32_t parent_set_visibility = parent_info->flags & ZEND_ACC_PPP_SET_MASK;
1461 /* Adding set protection is fine if it's the same or weaker than
1462 * the parents full property visibility. */
1463 if (!parent_set_visibility) {
1464 parent_set_visibility = zend_visibility_to_set_visibility(parent_info->flags & ZEND_ACC_PPP_MASK);
1465 }
1466 uint32_t child_set_visibility = child_info->flags & ZEND_ACC_PPP_SET_MASK;
1467 if (child_set_visibility > parent_set_visibility) {
1470 "Set access level of %s::$%s must be %s (as in class %s)%s",
1471 ZSTR_VAL(ce->name), ZSTR_VAL(key),
1472 zend_asymmetric_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name),
1473 !(parent_info->flags & ZEND_ACC_PPP_SET_MASK) ? "" : " or weaker");
1474 }
1475 }
1476
1477 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1478 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(key), zend_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1479 }
1480 if (!(child_info->flags & ZEND_ACC_STATIC) && !(parent_info->flags & ZEND_ACC_VIRTUAL)) {
1481 /* If we added hooks to the child property, we use the child's slot for
1482 * storage to keep the parent slot set to IS_UNDEF. This automatically
1483 * picks the slow path in the JIT. */
1484 bool use_child_prop = !parent_info->hooks && child_info->hooks;
1485
1486 if (use_child_prop && child_info->offset == ZEND_VIRTUAL_PROPERTY_OFFSET) {
1490 zval *property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(child_info->offset)];
1491 ZVAL_UNDEF(property_default_ptr);
1492 Z_PROP_FLAG_P(property_default_ptr) = IS_PROP_UNINIT;
1493 }
1494
1495 int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1496 if (child_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1497 /* Don't keep default properties in GC (they may be freed by opcache) */
1498 zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1499
1500 if (use_child_prop) {
1501 ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1502 } else {
1503 int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1504 ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1505 ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1506 }
1507 } else {
1508 /* Default value was removed in child, remove it from parent too. */
1509 if (ZEND_TYPE_IS_SET(child_info->type)) {
1510 ZVAL_UNDEF(&ce->default_properties_table[parent_num]);
1511 } else {
1512 ZVAL_NULL(&ce->default_properties_table[parent_num]);
1513 }
1514 }
1515
1516 if (!use_child_prop) {
1517 child_info->offset = parent_info->offset;
1518 }
1519 child_info->flags &= ~ZEND_ACC_VIRTUAL;
1520 }
1521
1522 if (parent_info->hooks || child_info->hooks) {
1523 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1524 inherit_property_hook(ce, parent_info, child_info, i);
1525 }
1526 }
1527
1528 prop_variance variance = prop_get_variance(parent_info);
1529 if (ZEND_TYPE_IS_SET(parent_info->type)) {
1530 inheritance_status status = verify_property_type_compatibility(
1531 parent_info, child_info, variance, true, false);
1533 add_property_compatibility_obligation(ce, child_info, parent_info, variance);
1534 }
1535 } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1537 "Type of %s::$%s must not be defined (as in class %s)",
1538 ZSTR_VAL(ce->name),
1539 ZSTR_VAL(key),
1540 ZSTR_VAL(parent_info->ce->name));
1541 }
1542 }
1543 } else {
1544 zend_function **hooks = parent_info->hooks;
1545 if (hooks) {
1546 ce->num_hooked_props++;
1547 if (parent_info->flags & ZEND_ACC_ABSTRACT) {
1549 }
1550 }
1551
1552 _zend_hash_append_ptr(&ce->properties_info, key, parent_info);
1553 }
1554}
1555/* }}} */
1556
1557static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1558{
1559 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1560 zend_error_noreturn(E_CORE_ERROR, "%s %s could not implement interface %s", zend_get_object_type_uc(ce), ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1561 }
1562 /* This should be prevented by the class lookup logic. */
1563 ZEND_ASSERT(ce != iface);
1564}
1565/* }}} */
1566
1567static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1568{
1569 /* expects interface to be contained in ce's interface list already */
1570 uint32_t i, ce_num, if_num = iface->num_interfaces;
1571 zend_class_entry *entry;
1572
1573 ce_num = ce->num_interfaces;
1574
1575 if (ce->type == ZEND_INTERNAL_CLASS) {
1576 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1577 } else {
1578 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1579 }
1580
1581 /* Inherit the interfaces, only if they're not already inherited by the class */
1582 while (if_num--) {
1583 entry = iface->interfaces[if_num];
1584 for (i = 0; i < ce_num; i++) {
1585 if (ce->interfaces[i] == entry) {
1586 break;
1587 }
1588 }
1589 if (i == ce_num) {
1590 ce->interfaces[ce->num_interfaces++] = entry;
1591 }
1592 }
1594
1595 /* and now call the implementing handlers */
1596 while (ce_num < ce->num_interfaces) {
1597 do_implement_interface(ce, ce->interfaces[ce_num++]);
1598 }
1599}
1600/* }}} */
1601
1602static void emit_incompatible_class_constant_error(
1603 const zend_class_constant *child, const zend_class_constant *parent, const zend_string *const_name) {
1604 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1606 "Type of %s::%s must be compatible with %s::%s of type %s",
1607 ZSTR_VAL(child->ce->name),
1608 ZSTR_VAL(const_name),
1609 ZSTR_VAL(parent->ce->name),
1610 ZSTR_VAL(const_name),
1611 ZSTR_VAL(type_str));
1612}
1613
1614static inheritance_status class_constant_types_compatible(const zend_class_constant *parent, const zend_class_constant *child)
1615{
1616 ZEND_ASSERT(ZEND_TYPE_IS_SET(parent->type));
1617
1618 if (!ZEND_TYPE_IS_SET(child->type)) {
1619 return INHERITANCE_ERROR;
1620 }
1621
1622 return zend_perform_covariant_type_check(child->ce, child->type, parent->ce, parent->type);
1623}
1624
1625static bool do_inherit_constant_check(
1626 zend_class_entry *ce, zend_class_constant *parent_constant, zend_string *name);
1627
1628static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
1629{
1632
1633 if (zv != NULL) {
1635 bool inherit = do_inherit_constant_check(ce, parent_const, name);
1636 ZEND_ASSERT(!inherit);
1637 } else if (!(ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE)) {
1638 if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1641 if (ce->parent->ce_flags & ZEND_ACC_IMMUTABLE) {
1642 c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1643 memcpy(c, parent_const, sizeof(zend_class_constant));
1644 parent_const = c;
1646 }
1647 }
1648 if (ce->type & ZEND_INTERNAL_CLASS) {
1649 c = pemalloc(sizeof(zend_class_constant), 1);
1650 memcpy(c, parent_const, sizeof(zend_class_constant));
1651 parent_const = c;
1652 }
1653 _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1654 }
1655}
1656/* }}} */
1657
1659{
1660 zend_property_info **table, *prop;
1661 size_t size;
1662 if (ce->default_properties_count == 0) {
1663 return;
1664 }
1665
1668 if (ce->type == ZEND_USER_CLASS) {
1669 ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1670 } else {
1671 ce->properties_info_table = table = pemalloc(size, 1);
1672 }
1673
1674 /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1675 memset(table, 0, size);
1676
1677 if (ce->parent && ce->parent->default_properties_count != 0) {
1678 zend_property_info **parent_table = ce->parent->properties_info_table;
1679 memcpy(
1680 table, parent_table,
1682 );
1683
1684 /* Child did not add any new properties, we are done */
1686 return;
1687 }
1688 }
1689
1691 if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0
1692 && !(prop->flags & ZEND_ACC_VIRTUAL)) {
1693 uint32_t prop_table_offset = OBJ_PROP_TO_NUM(!(prop->prototype->flags & ZEND_ACC_VIRTUAL) ? prop->prototype->offset : prop->offset);
1694 table[prop_table_offset] = prop;
1695 }
1697}
1698
1700{
1701 if (!prop_info->hooks) {
1702 return;
1703 }
1704 bool abstract_error = prop_info->flags & ZEND_ACC_ABSTRACT;
1705 /* We specified a default value (otherwise offset would be -1), but the virtual flag wasn't
1706 * removed during inheritance. */
1710 } else {
1712 "Cannot specify default value for virtual hooked property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1713 }
1714 }
1715 /* If the property turns backed during inheritance and no type and default value are set, we want
1716 * the default value to be null. */
1717 if (!(prop_info->flags & ZEND_ACC_VIRTUAL)
1718 && !ZEND_TYPE_IS_SET(prop_info->type)
1721 }
1722 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
1723 zend_function *func = prop_info->hooks[i];
1724 if (func) {
1726 && (func->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)
1727 && !(prop_info->flags & ZEND_ACC_VIRTUAL)
1728 && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
1729 zend_error_noreturn(E_COMPILE_ERROR, "Get hook of backed property %s::%s with set hook may not return by reference",
1730 ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1731 }
1732 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
1733 abstract_error = false;
1734 }
1735 }
1736 }
1737 if (abstract_error) {
1739 "Abstract property %s::$%s must specify at least one abstract hook", ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1740 }
1741 if ((prop_info->flags & ZEND_ACC_VIRTUAL)
1742 && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)
1744 const char *prefix = !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]
1745 ? "Write-only" : "Read-only";
1747 "%s virtual property %s::$%s must not specify asymmetric visibility",
1748 prefix, ZSTR_VAL(ce->name), ZSTR_VAL(prop_name));
1749 }
1750}
1751
1753{
1754 zend_error_noreturn(E_COMPILE_ERROR, "Type of parameter $%s of hook %s::$%s::set must be compatible with property type",
1755 ZSTR_VAL(value_param_name), ZSTR_VAL(class_name), zend_get_unmangled_property_name(prop_name));
1756}
1757
1759{
1760 zend_string *value_param_name = prop_info->hooks[ZEND_PROPERTY_HOOK_SET]->op_array.arg_info[0].name;
1761 zend_hooked_property_variance_error_ex(value_param_name, prop_info->ce->name, prop_info->name);
1762}
1763
1765{
1767
1768 zend_arg_info *value_arg_info = &func->op_array.arg_info[0];
1769 if (!ZEND_TYPE_IS_SET(value_arg_info->type)) {
1770 return INHERITANCE_SUCCESS;
1771 }
1772
1773 if (!ZEND_TYPE_IS_SET(prop_info->type)) {
1774 return INHERITANCE_ERROR;
1775 }
1776
1777 zend_class_entry *ce = prop_info->ce;
1778 return zend_perform_covariant_type_check(ce, prop_info->type, ce, value_arg_info->type);
1779}
1780
1781#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
1782/* Hooked properties set get_iterator, which causes issues on for shm
1783 * reattachment. Avoid early-binding on Windows and set get_iterator during
1784 * inheritance. The linked class may not use inheritance cache. */
1785static void zend_link_hooked_object_iter(zend_class_entry *ce) {
1786 if (!ce->get_iterator && ce->num_hooked_props) {
1789 if (CG(current_linking_class) == ce) {
1790# if ZEND_DEBUG
1791 /* This check is executed before inheriting any elements that can
1792 * track dependencies. */
1794 ZEND_ASSERT(!ht);
1795# endif
1796 CG(current_linking_class) = NULL;
1797 }
1798 }
1799}
1800#endif
1801
1802ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked) /* {{{ */
1803{
1804 zend_property_info *property_info;
1807
1809 /* Interface can only inherit other interfaces */
1810 if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
1811 zend_error_noreturn(E_COMPILE_ERROR, "Interface %s cannot extend class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1812 }
1814 /* Class must not extend a final class */
1815 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1816 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend final class %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1817 }
1818
1819 /* Class declaration must not extend traits or interfaces */
1820 if ((parent_ce->ce_flags & ZEND_ACC_INTERFACE) || (parent_ce->ce_flags & ZEND_ACC_TRAIT)) {
1821 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend %s %s",
1822 ZSTR_VAL(ce->name), parent_ce->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "trait", ZSTR_VAL(parent_ce->name)
1823 );
1824 }
1825 }
1826
1828 zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1829 ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "Readonly" : "Non-readonly", ZSTR_VAL(ce->name),
1830 parent_ce->ce_flags & ZEND_ACC_READONLY_CLASS ? "readonly" : "non-readonly", ZSTR_VAL(parent_ce->name)
1831 );
1832 }
1833
1834 if (ce->parent_name) {
1836 }
1837 ce->parent = parent_ce;
1840
1841 /* Inherit properties */
1842 if (parent_ce->default_properties_count) {
1843 zval *src, *dst, *end;
1844
1845 if (ce->default_properties_count) {
1846 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1848 end = table + parent_ce->default_properties_count;
1849 dst = end + ce->default_properties_count;
1850 ce->default_properties_table = table;
1851 do {
1852 dst--;
1853 src--;
1854 ZVAL_COPY_VALUE_PROP(dst, src);
1855 } while (dst != end);
1856 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1858 } else {
1859 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1860 dst = end + parent_ce->default_properties_count;
1862 }
1863 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1864 if (UNEXPECTED(parent_ce->type != ce->type)) {
1865 /* User class extends internal */
1866 do {
1867 dst--;
1868 src--;
1869 /* We don't have to account for refcounting because
1870 * zend_declare_typed_property() disallows refcounted defaults for internal classes. */
1872 ZVAL_COPY_VALUE_PROP(dst, src);
1873 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1876 }
1877 continue;
1878 } while (dst != end);
1879 } else {
1880 do {
1881 dst--;
1882 src--;
1883 ZVAL_COPY_PROP(dst, src);
1884 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1887 }
1888 continue;
1889 } while (dst != end);
1890 }
1892 }
1893
1894 if (parent_ce->default_static_members_count) {
1895 zval *src, *dst, *end;
1896
1900 end = table + parent_ce->default_static_members_count;
1902 ce->default_static_members_table = table;
1903 do {
1904 dst--;
1905 src--;
1906 ZVAL_COPY_VALUE(dst, src);
1907 } while (dst != end);
1908 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1910 } else {
1911 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1912 dst = end + parent_ce->default_static_members_count;
1914 }
1915 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1916 do {
1917 dst--;
1918 src--;
1919 if (Z_TYPE_P(src) == IS_INDIRECT) {
1920 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1921 } else {
1922 ZVAL_INDIRECT(dst, src);
1923 }
1924 if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1927 }
1928 } while (dst != end);
1930 if (!ZEND_MAP_PTR(ce->static_members_table)) {
1931 if (ce->type == ZEND_INTERNAL_CLASS &&
1933 ZEND_MAP_PTR_NEW(ce->static_members_table);
1934 }
1935 }
1936 }
1937
1938 ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, property_info) {
1939 if (property_info->ce == ce) {
1940 if (property_info->flags & ZEND_ACC_STATIC) {
1941 property_info->offset += parent_ce->default_static_members_count;
1942 } else if (property_info->offset != ZEND_VIRTUAL_PROPERTY_OFFSET) {
1943 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1944 }
1945 }
1947
1948 if (zend_hash_num_elements(&parent_ce->properties_info)) {
1950 zend_hash_num_elements(&ce->properties_info) +
1951 zend_hash_num_elements(&parent_ce->properties_info), 0);
1952
1953 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1954 do_inherit_property(property_info, key, ce);
1956 }
1957
1958 if (ce->num_hooked_props) {
1960 if (property_info->ce == ce && property_info->hooks) {
1961 zend_verify_hooked_property(ce, property_info, key);
1962 }
1964 }
1965
1966 if (zend_hash_num_elements(&parent_ce->constants_table)) {
1968
1970 zend_hash_num_elements(&ce->constants_table) +
1971 zend_hash_num_elements(&parent_ce->constants_table), 0);
1972
1974 do_inherit_class_constant(key, c, ce);
1976 }
1977
1978 if (zend_hash_num_elements(&parent_ce->function_table)) {
1980 zend_hash_num_elements(&ce->function_table) +
1981 zend_hash_num_elements(&parent_ce->function_table), 0);
1982 uint32_t flags =
1987
1988 if (!checked) {
1990 }
1992 do_inherit_method(key, func, ce, 0, flags);
1994 }
1995
1996 do_inherit_parent_constructor(ce);
1997
1998 if (ce->type == ZEND_INTERNAL_CLASS) {
1999 if (parent_ce->num_interfaces) {
2000 zend_do_inherit_interfaces(ce, parent_ce);
2001 }
2002
2005 }
2006 }
2008}
2009/* }}} */
2010
2011static zend_always_inline bool check_trait_property_or_constant_value_compatibility(zend_class_entry *ce, zval *op1, zval *op2) /* {{{ */
2012{
2013 bool is_compatible;
2014 zval op1_tmp, op2_tmp;
2015
2016 /* if any of the values is a constant, we try to resolve it */
2018 ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2019 if (UNEXPECTED(zval_update_constant_ex(&op1_tmp, ce) != SUCCESS)) {
2020 zval_ptr_dtor(&op1_tmp);
2021 return false;
2022 }
2023 op1 = &op1_tmp;
2024 }
2026 ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2027 if (UNEXPECTED(zval_update_constant_ex(&op2_tmp, ce) != SUCCESS)) {
2028 zval_ptr_dtor(&op2_tmp);
2029 return false;
2030 }
2031 op2 = &op2_tmp;
2032 }
2033
2034 is_compatible = fast_is_identical_function(op1, op2);
2035
2036 if (op1 == &op1_tmp) {
2037 zval_ptr_dtor_nogc(&op1_tmp);
2038 }
2039 if (op2 == &op2_tmp) {
2040 zval_ptr_dtor_nogc(&op2_tmp);
2041 }
2042
2043 return is_compatible;
2044}
2045/* }}} */
2046
2048static bool do_inherit_constant_check(
2050) {
2052 if (zv == NULL) {
2053 return true;
2054 }
2055
2056 zend_class_constant *child_constant = Z_PTR_P(zv);
2057 if (parent_constant->ce != child_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) {
2058 zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s",
2059 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2060 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name)
2061 );
2062 }
2063
2064 if (child_constant->ce != parent_constant->ce && child_constant->ce != ce) {
2066 "%s %s inherits both %s::%s and %s::%s, which is ambiguous",
2067 zend_get_object_type_uc(ce),
2068 ZSTR_VAL(ce->name),
2069 ZSTR_VAL(child_constant->ce->name), ZSTR_VAL(name),
2070 ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name));
2071 }
2072
2073 if (UNEXPECTED((ZEND_CLASS_CONST_FLAGS(child_constant) & ZEND_ACC_PPP_MASK) > (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PPP_MASK))) {
2074 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in %s %s)%s",
2075 ZSTR_VAL(ce->name), ZSTR_VAL(name),
2077 zend_get_object_type(parent_constant->ce),
2078 ZSTR_VAL(parent_constant->ce->name),
2079 (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PUBLIC) ? "" : " or weaker"
2080 );
2081 }
2082
2083 if (!(ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_PRIVATE) && ZEND_TYPE_IS_SET(parent_constant->type)) {
2084 inheritance_status status = class_constant_types_compatible(parent_constant, child_constant);
2085 if (status == INHERITANCE_ERROR) {
2086 emit_incompatible_class_constant_error(child_constant, parent_constant, name);
2087 } else if (status == INHERITANCE_UNRESOLVED) {
2088 add_class_constant_compatibility_obligation(ce, child_constant, parent_constant, name);
2089 }
2090 }
2091
2092 return false;
2093}
2094/* }}} */
2095
2096static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2097{
2098 if (do_inherit_constant_check(ce, c, name)) {
2100 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
2103 if (iface->ce_flags & ZEND_ACC_IMMUTABLE) {
2104 ct = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
2105 memcpy(ct, c, sizeof(zend_class_constant));
2106 c = ct;
2108 }
2109 }
2110 if (ce->type & ZEND_INTERNAL_CLASS) {
2111 ct = pemalloc(sizeof(zend_class_constant), 1);
2112 memcpy(ct, c, sizeof(zend_class_constant));
2113 c = ct;
2114 }
2115 zend_hash_update_ptr(&ce->constants_table, name, c);
2116 }
2117}
2118/* }}} */
2119
2120static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
2121{
2126
2127 if (!(ce->ce_flags & ZEND_ACC_INTERFACE)) {
2128 /* We are not setting the prototype of overridden interface methods because of abstract
2129 * constructors. See Zend/tests/interface_constructor_prototype_001.phpt. */
2130 flags |=
2134 } else {
2135 flags |=
2138 }
2139
2141 do_inherit_iface_constant(key, c, ce, iface);
2143
2145 do_inherit_method(key, func, ce, 1, flags);
2147
2149 zend_hash_num_elements(&ce->properties_info) +
2150 zend_hash_num_elements(&iface->properties_info), 0);
2151
2152 zend_property_info *prop;
2154 do_inherit_property(prop, key, ce);
2156
2157 do_implement_interface(ce, iface);
2158 if (iface->num_interfaces) {
2159 zend_do_inherit_interfaces(ce, iface);
2160 }
2161}
2162/* }}} */
2163
2165{
2166 uint32_t i, ignore = 0;
2167 uint32_t current_iface_num = ce->num_interfaces;
2168 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
2171
2173
2174 for (i = 0; i < ce->num_interfaces; i++) {
2175 if (ce->interfaces[i] == NULL) {
2176 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
2177 i--;
2178 } else if (ce->interfaces[i] == iface) {
2179 if (EXPECTED(i < parent_iface_num)) {
2180 ignore = 1;
2181 } else {
2182 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2183 }
2184 }
2185 }
2186 if (ignore) {
2187 /* Check for attempt to redeclare interface constants */
2189 do_inherit_constant_check(ce, c, key);
2191 } else {
2192 if (ce->num_interfaces >= current_iface_num) {
2193 if (ce->type == ZEND_INTERNAL_CLASS) {
2194 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2195 } else {
2196 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
2197 }
2198 }
2199 ce->interfaces[ce->num_interfaces++] = iface;
2200
2201 do_interface_implementation(ce, iface);
2202 }
2203}
2204/* }}} */
2205
2206static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
2207{
2208 zend_class_entry *iface;
2209 uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
2210 uint32_t num_interfaces = num_parent_interfaces;
2213 uint32_t i, j;
2214
2215 for (i = 0; i < ce->num_interfaces; i++) {
2216 iface = interfaces[num_parent_interfaces + i];
2217 if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
2218 add_dependency_obligation(ce, iface);
2219 }
2220 if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
2221 efree(interfaces);
2222 zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2223 return;
2224 }
2225 for (j = 0; j < num_interfaces; j++) {
2226 if (interfaces[j] == iface) {
2227 if (j >= num_parent_interfaces) {
2228 efree(interfaces);
2229 zend_error_noreturn(E_COMPILE_ERROR, "%s %s cannot implement previously implemented interface %s",
2230 zend_get_object_type_uc(ce),
2231 ZSTR_VAL(ce->name),
2232 ZSTR_VAL(iface->name));
2233 return;
2234 }
2235 /* skip duplications */
2237 do_inherit_constant_check(ce, c, key);
2239
2240 iface = NULL;
2241 break;
2242 }
2243 }
2244 if (iface) {
2245 interfaces[num_interfaces] = iface;
2246 num_interfaces++;
2247 }
2248 }
2249
2250 if (!(ce->ce_flags & ZEND_ACC_CACHED)) {
2251 for (i = 0; i < ce->num_interfaces; i++) {
2254 }
2256 }
2257
2258 ce->num_interfaces = num_interfaces;
2259 ce->interfaces = interfaces;
2261
2262 for (i = 0; i < num_parent_interfaces; i++) {
2263 do_implement_interface(ce, ce->interfaces[i]);
2264 }
2265 /* Note that new interfaces can be added during this loop due to interface inheritance.
2266 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
2267 for (; i < num_interfaces; i++) {
2268 do_interface_implementation(ce, ce->interfaces[i]);
2269 }
2270}
2271/* }}} */
2272
2273
2275{
2276 zend_function *f;
2277
2278 if (ce->ce_flags & ZEND_ACC_TRAIT) {
2279 return;
2280 }
2281
2285
2288 "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2290 }
2292
2293 if (ce->num_hooked_props) {
2294 zend_property_info *prop;
2296 if (!prop->hooks) {
2297 continue;
2298 }
2299 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2300 f = prop->hooks[i];
2301 if (f && f->common.fn_flags & ZEND_ACC_OVERRIDE) {
2303
2306 "%s::%s() has #[\\Override] attribute, but no matching parent method exists",
2308 }
2309 }
2311 }
2312}
2313
2314
2315static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
2316{
2317 /* self in trait methods should be resolved to the using class, not the trait. */
2318 return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
2319}
2320
2321static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
2322{
2323 zend_function *existing_fn = NULL;
2324 zend_function *new_fn;
2325 bool check_inheritance = false;
2326
2327 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
2328 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
2329 * of where it is coming from there is no conflict and we do not need to add it again */
2330 if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
2331 (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
2332 (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
2333 return;
2334 }
2335
2336 /* Abstract method signatures from the trait must be satisfied. */
2337 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2338 /* "abstract private" methods in traits were not available prior to PHP 8.
2339 * As such, "abstract protected" was sometimes used to indicate trait requirements,
2340 * even though the "implementing" method was private. Do not check visibility
2341 * requirements to maintain backwards-compatibility with such usage.
2342 */
2343 do_inheritance_check_on_method(
2344 existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
2346 return;
2347 }
2348
2349 if (existing_fn->common.scope == ce) {
2350 /* members from the current class override trait methods */
2351 return;
2352 } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
2353 && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
2354 /* two traits can't define the same non-abstract method */
2355 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
2357 ZSTR_VAL(ce->name), ZSTR_VAL(name),
2358 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
2359 } else {
2360 check_inheritance = true;
2361 }
2362 }
2363
2365 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
2366 memcpy(new_fn, fn, sizeof(zend_internal_function));
2368 } else {
2369 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2370 memcpy(new_fn, fn, sizeof(zend_op_array));
2372 }
2374
2375 /* Reassign method name, in case it is an alias. */
2376 new_fn->common.function_name = name;
2377 function_add_ref(new_fn);
2378 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
2379 zend_add_magic_method(ce, fn, key);
2380
2381 if (check_inheritance) {
2382 /* Inherited members are overridden by members inserted by traits.
2383 * Check whether the trait method fulfills the inheritance requirements. */
2385 if (!(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
2388 }
2389 do_inheritance_check_on_method(
2390 fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
2391 ce, NULL, flags);
2392 }
2393}
2394/* }}} */
2395
2396static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
2397{
2399
2400 fn->common.scope = ce;
2401
2402 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
2404 }
2407 }
2408 }
2409}
2410/* }}} */
2411
2412static void zend_traits_check_private_final_inheritance(uint32_t original_fn_flags, zend_function *fn_copy, zend_string *name)
2413{
2414 /* If the function was originally already private+final, then it will have
2415 * already been warned about. Only emit this error when the used trait method
2416 * explicitly became final, avoiding errors for `as private` where it was
2417 * already final. */
2418 if (!(original_fn_flags & ZEND_ACC_FINAL)
2421 zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
2422 }
2423}
2424
2425static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
2426{
2427 zend_trait_alias *alias, **alias_ptr;
2429 zend_function fn_copy;
2430 int i;
2431
2432 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
2433 if (ce->trait_aliases) {
2434 alias_ptr = ce->trait_aliases;
2435 alias = *alias_ptr;
2436 i = 0;
2437 while (alias) {
2438 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2439 if (alias->alias != NULL
2440 && fn->common.scope == aliases[i]
2442 ) {
2443 fn_copy = *fn;
2444 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2445 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2446 } else {
2447 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2448 }
2449
2450 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, alias->alias);
2451
2452 lcname = zend_string_tolower(alias->alias);
2453 zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
2455 }
2456 alias_ptr++;
2457 alias = *alias_ptr;
2458 i++;
2459 }
2460 }
2461
2462 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
2463 /* is not in hashtable, thus, function is not to be excluded */
2464 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
2465
2466 /* apply aliases which have not alias name, just setting visibility */
2467 if (ce->trait_aliases) {
2468 alias_ptr = ce->trait_aliases;
2469 alias = *alias_ptr;
2470 i = 0;
2471 while (alias) {
2472 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
2473 if (alias->alias == NULL && alias->modifiers != 0
2474 && fn->common.scope == aliases[i]
2476 ) {
2477 if (alias->modifiers & ZEND_ACC_PPP_MASK) {
2478 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
2479 } else {
2480 fn_copy.common.fn_flags = alias->modifiers | fn->common.fn_flags;
2481 }
2482 }
2483 alias_ptr++;
2484 alias = *alias_ptr;
2485 i++;
2486 }
2487 }
2488
2489 zend_traits_check_private_final_inheritance(fn->common.fn_flags, &fn_copy, fnname);
2490
2491 zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
2492 }
2493}
2494/* }}} */
2495
2496static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
2497{
2498 uint32_t i;
2499
2500 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
2501 zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", ZSTR_VAL(trait->name));
2502 return 0;
2503 }
2504
2505 for (i = 0; i < ce->num_traits; i++) {
2506 if (traits[i] == trait) {
2507 return i;
2508 }
2509 }
2510 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
2511 return 0;
2512}
2513/* }}} */
2514
2515static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
2516{
2517 size_t i, j = 0;
2518 zend_trait_precedence **precedences;
2519 zend_trait_precedence *cur_precedence;
2520 zend_trait_method_reference *cur_method_ref;
2521 zend_string *lc_trait_name;
2523 HashTable **exclude_tables = NULL;
2524 zend_class_entry **aliases = NULL;
2525 zend_class_entry *trait;
2526
2527 /* resolve class references */
2528 if (ce->trait_precedences) {
2529 exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
2530 i = 0;
2531 precedences = ce->trait_precedences;
2532 ce->trait_precedences = NULL;
2533 while ((cur_precedence = precedences[i])) {
2535 cur_method_ref = &cur_precedence->trait_method;
2536 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2537 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2538 zend_string_release_ex(lc_trait_name, 0);
2539 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2540 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2541 }
2542 zend_check_trait_usage(ce, trait, traits);
2543
2545 lcname = zend_string_tolower(cur_method_ref->method_name);
2546 if (!zend_hash_exists(&trait->function_table, lcname)) {
2548 "A precedence rule was defined for %s::%s but this method does not exist",
2549 ZSTR_VAL(trait->name),
2550 ZSTR_VAL(cur_method_ref->method_name));
2551 }
2552
2559
2560 for (j = 0; j < cur_precedence->num_excludes; j++) {
2561 zend_string* class_name = cur_precedence->exclude_class_names[j];
2562 zend_class_entry *exclude_ce;
2563 uint32_t trait_num;
2564
2565 lc_trait_name = zend_string_tolower(class_name);
2566 exclude_ce = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2567 zend_string_release_ex(lc_trait_name, 0);
2568 if (!exclude_ce || !(exclude_ce->ce_flags & ZEND_ACC_LINKED)) {
2569 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
2570 }
2571 trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
2572 if (!exclude_tables[trait_num]) {
2573 ALLOC_HASHTABLE(exclude_tables[trait_num]);
2574 zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
2575 }
2576 if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
2577 zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", ZSTR_VAL(precedences[i]->trait_method.method_name), ZSTR_VAL(exclude_ce->name));
2578 }
2579
2580 /* make sure that the trait method is not from a class mentioned in
2581 exclude_from_classes, for consistency */
2582 if (trait == exclude_ce) {
2584 "Inconsistent insteadof definition. "
2585 "The method %s is to be used from %s, but %s is also on the exclude list",
2586 ZSTR_VAL(cur_method_ref->method_name),
2587 ZSTR_VAL(trait->name),
2588 ZSTR_VAL(trait->name));
2589 }
2590 }
2592 i++;
2593 }
2594 ce->trait_precedences = precedences;
2595 }
2596
2597 if (ce->trait_aliases) {
2598 i = 0;
2599 while (ce->trait_aliases[i]) {
2600 i++;
2601 }
2602 aliases = ecalloc(i, sizeof(zend_class_entry*));
2603 i = 0;
2604 while (ce->trait_aliases[i]) {
2605 zend_trait_alias *cur_alias = ce->trait_aliases[i];
2606 cur_method_ref = &ce->trait_aliases[i]->trait_method;
2607 lcname = zend_string_tolower(cur_method_ref->method_name);
2608 if (cur_method_ref->class_name) {
2609 /* For all aliases with an explicit class name, resolve the class now. */
2610 lc_trait_name = zend_string_tolower(cur_method_ref->class_name);
2611 trait = zend_hash_find_ptr(EG(class_table), lc_trait_name);
2612 zend_string_release_ex(lc_trait_name, 0);
2613 if (!trait || !(trait->ce_flags & ZEND_ACC_LINKED)) {
2614 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
2615 }
2616 zend_check_trait_usage(ce, trait, traits);
2617 aliases[i] = trait;
2618
2619 /* And, ensure that the referenced method is resolvable, too. */
2620 if (!zend_hash_exists(&trait->function_table, lcname)) {
2621 zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name));
2622 }
2623 } else {
2624 /* Find out which trait this method refers to. */
2625 trait = NULL;
2626 for (j = 0; j < ce->num_traits; j++) {
2627 if (traits[j]) {
2628 if (zend_hash_exists(&traits[j]->function_table, lcname)) {
2629 if (!trait) {
2630 trait = traits[j];
2631 continue;
2632 }
2633
2635 "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
2636 ZSTR_VAL(cur_method_ref->method_name),
2637 ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
2638 ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
2639 ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
2640 }
2641 }
2642 }
2643
2644 /* Non-absolute method reference refers to method that does not exist. */
2645 if (!trait) {
2646 if (cur_alias->alias) {
2648 "An alias (%s) was defined for method %s(), but this method does not exist",
2649 ZSTR_VAL(cur_alias->alias),
2650 ZSTR_VAL(cur_alias->trait_method.method_name));
2651 } else {
2653 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
2654 ZSTR_VAL(cur_alias->trait_method.method_name));
2655 }
2656 }
2657
2658 aliases[i] = trait;
2659 }
2661 i++;
2662 }
2663 }
2664
2665 *exclude_tables_ptr = exclude_tables;
2666 *aliases_ptr = aliases;
2667}
2668/* }}} */
2669
2670static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
2671{
2672 uint32_t i;
2674 zend_function *fn;
2675
2676 if (exclude_tables) {
2677 for (i = 0; i < ce->num_traits; i++) {
2678 if (traits[i]) {
2679 /* copies functions, applies defined aliasing, and excludes unused trait methods */
2680 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2681 zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
2683
2684 if (exclude_tables[i]) {
2685 zend_hash_destroy(exclude_tables[i]);
2686 FREE_HASHTABLE(exclude_tables[i]);
2687 exclude_tables[i] = NULL;
2688 }
2689 }
2690 }
2691 } else {
2692 for (i = 0; i < ce->num_traits; i++) {
2693 if (traits[i]) {
2694 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
2695 zend_traits_copy_functions(key, fn, ce, NULL, aliases);
2697 }
2698 }
2699 }
2700
2702 zend_fixup_trait_method(fn, ce);
2704}
2705/* }}} */
2706
2707static const zend_class_entry* find_first_constant_definition(const zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *constant_name, const zend_class_entry *colliding_ce) /* {{{ */
2708{
2709 /* This function is used to show the place of the existing conflicting
2710 * definition in error messages when conflicts occur. Since trait constants
2711 * are flattened into the constants table of the composing class, and thus
2712 * we lose information about which constant was defined in which trait, a
2713 * process like this is needed to find the location of the first definition
2714 * of the constant from traits.
2715 */
2716 size_t i;
2717
2718 if (colliding_ce == ce) {
2719 for (i = 0; i < current_trait; i++) {
2720 if (traits[i]
2721 && zend_hash_exists(&traits[i]->constants_table, constant_name)) {
2722 return traits[i];
2723 }
2724 }
2725 }
2726 /* Traits don't have it, then the composing class (or trait) itself has it. */
2727 return colliding_ce;
2728}
2729/* }}} */
2730
2731static void emit_incompatible_trait_constant_error(
2732 const zend_class_entry *ce, const zend_class_constant *existing_constant, const zend_class_constant *trait_constant, zend_string *name,
2733 zend_class_entry **traits, size_t current_trait
2734) {
2736 "%s and %s define the same constant (%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2737 ZSTR_VAL(find_first_constant_definition(ce, traits, current_trait, name, existing_constant->ce)->name),
2738 ZSTR_VAL(trait_constant->ce->name),
2739 ZSTR_VAL(name),
2740 ZSTR_VAL(ce->name)
2741 );
2742}
2743
2744static bool do_trait_constant_check(
2745 zend_class_entry *ce, zend_class_constant *trait_constant, zend_string *name, zend_class_entry **traits, size_t current_trait
2746) {
2747 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL;
2748
2750 if (zv == NULL) {
2751 /* No existing constant of the same name, so this one can be added */
2752 return true;
2753 }
2754
2755 zend_class_constant *existing_constant = Z_PTR_P(zv);
2756
2757 if ((ZEND_CLASS_CONST_FLAGS(trait_constant) & flags_mask) != (ZEND_CLASS_CONST_FLAGS(existing_constant) & flags_mask)) {
2758 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2759 return false;
2760 }
2761
2762 if (ZEND_TYPE_IS_SET(trait_constant->type) != ZEND_TYPE_IS_SET(existing_constant->type)) {
2763 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2764 return false;
2765 } else if (ZEND_TYPE_IS_SET(trait_constant->type)) {
2766 inheritance_status status1 = zend_perform_covariant_type_check(ce, existing_constant->type, traits[current_trait], trait_constant->type);
2767 inheritance_status status2 = zend_perform_covariant_type_check(traits[current_trait], trait_constant->type, ce, existing_constant->type);
2768 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
2769 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2770 return false;
2771 }
2772 }
2773
2774 if (!check_trait_property_or_constant_value_compatibility(ce, &trait_constant->value, &existing_constant->value)) {
2775 /* There is an existing constant of the same name, and it conflicts with the new one, so let's throw a fatal error */
2776 emit_incompatible_trait_constant_error(ce, existing_constant, trait_constant, name, traits, current_trait);
2777 return false;
2778 }
2779
2780 /* There is an existing constant which is compatible with the new one, so no need to add it */
2781 return false;
2782}
2783
2784static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2785{
2786 size_t i;
2787
2788 for (i = 0; i < ce->num_traits; i++) {
2789 zend_string *constant_name;
2791
2792 if (!traits[i]) {
2793 continue;
2794 }
2795
2796 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->constants_table, constant_name, constant) {
2797 if (do_trait_constant_check(ce, constant, constant_name, traits, i)) {
2799
2800 ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant));
2801 memcpy(ct, constant, sizeof(zend_class_constant));
2802 constant = ct;
2803
2804 if (Z_TYPE(constant->value) == IS_CONSTANT_AST) {
2807 }
2808
2809 /* Unlike interface implementations and class inheritances,
2810 * access control of the trait constants is done by the scope
2811 * of the composing class. So let's replace the ce here.
2812 */
2813 constant->ce = ce;
2814
2815 Z_TRY_ADDREF(constant->value);
2816 constant->doc_comment = constant->doc_comment ? zend_string_copy(constant->doc_comment) : NULL;
2817 if (constant->attributes && (!(GC_FLAGS(constant->attributes) & IS_ARRAY_IMMUTABLE))) {
2818 GC_ADDREF(constant->attributes);
2819 }
2820
2821 zend_hash_update_ptr(&ce->constants_table, constant_name, constant);
2822 }
2824 }
2825}
2826/* }}} */
2827
2828static const zend_class_entry* find_first_property_definition(const zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, const zend_class_entry *colliding_ce) /* {{{ */
2829{
2830 size_t i;
2831
2832 if (colliding_ce == ce) {
2833 for (i = 0; i < current_trait; i++) {
2834 if (traits[i]
2835 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
2836 return traits[i];
2837 }
2838 }
2839 }
2840
2841 return colliding_ce;
2842}
2843/* }}} */
2844
2845static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2846{
2847 size_t i;
2848 zend_property_info *property_info;
2849 const zend_property_info *colliding_prop;
2850 zend_property_info *new_prop;
2851 zend_string* prop_name;
2852 zval* prop_value;
2853 zend_string *doc_comment;
2854
2855 /* In the following steps the properties are inserted into the property table
2856 * for that, a very strict approach is applied:
2857 * - check for compatibility, if not compatible with any property in class -> fatal
2858 * - if compatible, then strict notice
2859 */
2860 for (i = 0; i < ce->num_traits; i++) {
2861 if (!traits[i]) {
2862 continue;
2863 }
2864 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&traits[i]->properties_info, prop_name, property_info) {
2865 uint32_t flags = property_info->flags;
2866
2867 /* next: check for conflicts with current class */
2868 if ((colliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
2869 if ((colliding_prop->flags & ZEND_ACC_PRIVATE) && colliding_prop->ce != ce) {
2870 zend_hash_del(&ce->properties_info, prop_name);
2872 } else {
2873 bool is_compatible = false;
2874 uint32_t flags_mask = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
2875
2876 if (colliding_prop->hooks || property_info->hooks) {
2878 "%s and %s define the same hooked property ($%s) in the composition of %s. Conflict resolution between hooked properties is currently not supported. Class was composed",
2879 ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2880 ZSTR_VAL(property_info->ce->name),
2881 ZSTR_VAL(prop_name),
2882 ZSTR_VAL(ce->name));
2883 }
2884
2885 if ((colliding_prop->flags & flags_mask) == (flags & flags_mask) &&
2886 verify_property_type_compatibility(property_info, colliding_prop, PROP_INVARIANT, false, false) == INHERITANCE_SUCCESS
2887 ) {
2888 /* the flags are identical, thus, the properties may be compatible */
2889 zval *op1, *op2;
2890
2891 if (flags & ZEND_ACC_STATIC) {
2892 op1 = &ce->default_static_members_table[colliding_prop->offset];
2893 op2 = &traits[i]->default_static_members_table[property_info->offset];
2896 } else {
2897 op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(colliding_prop->offset)];
2898 op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2899 }
2900 is_compatible = check_trait_property_or_constant_value_compatibility(ce, op1, op2);
2901 }
2902
2903 if (!is_compatible) {
2905 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2906 ZSTR_VAL(find_first_property_definition(ce, traits, i, prop_name, colliding_prop->ce)->name),
2907 ZSTR_VAL(property_info->ce->name),
2908 ZSTR_VAL(prop_name),
2909 ZSTR_VAL(ce->name));
2910 }
2911 if (!(flags & ZEND_ACC_STATIC)) {
2912 continue;
2913 }
2914 }
2915 }
2916
2917 if ((ce->ce_flags & ZEND_ACC_READONLY_CLASS) && !(property_info->flags & ZEND_ACC_READONLY)) {
2919 "Readonly class %s cannot use trait with a non-readonly property %s::$%s",
2920 ZSTR_VAL(ce->name),
2921 ZSTR_VAL(property_info->ce->name),
2922 ZSTR_VAL(prop_name)
2923 );
2924 }
2925
2926 /* property not found, so lets add it */
2927 zval tmp_prop_value;
2928 if (!(flags & ZEND_ACC_VIRTUAL)) {
2929 if (flags & ZEND_ACC_STATIC) {
2930 prop_value = &traits[i]->default_static_members_table[property_info->offset];
2931 ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2932 } else {
2933 prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2934 }
2935 Z_TRY_ADDREF_P(prop_value);
2936 } else {
2937 prop_value = &tmp_prop_value;
2938 ZVAL_UNDEF(&tmp_prop_value);
2939 }
2940 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2941
2942 zend_type type = property_info->type;
2943 /* Assumption: only userland classes can use traits, as such the type must be arena allocated */
2944 zend_type_copy_ctor(&type, /* use arena */ true, /* persistent */ false);
2945 new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2946
2947 if (property_info->attributes) {
2948 new_prop->attributes = property_info->attributes;
2949
2950 if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2951 GC_ADDREF(new_prop->attributes);
2952 }
2953 }
2954 if (property_info->hooks) {
2955 zend_function **hooks = new_prop->hooks =
2956 zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2957 memcpy(hooks, property_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
2958 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
2959 if (hooks[i]) {
2960 zend_function *old_fn = hooks[i];
2961
2962 /* Hooks are not yet supported for internal properties. */
2964
2965 /* Copy the function, because we need to adjust the scope. */
2966 zend_function *new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
2967 memcpy(new_fn, old_fn, sizeof(zend_op_array));
2970 new_fn->common.prop_info = new_prop;
2971 function_add_ref(new_fn);
2972
2973 zend_fixup_trait_method(new_fn, ce);
2974
2975 hooks[i] = new_fn;
2976 }
2977 }
2979 ce->num_hooked_props++;
2980 }
2982 }
2983}
2984/* }}} */
2985
2986static void zend_do_bind_traits(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
2987{
2988 HashTable **exclude_tables;
2989 zend_class_entry **aliases;
2990
2991 ZEND_ASSERT(ce->num_traits > 0);
2992
2993 /* complete initialization of trait structures in ce */
2994 zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2995
2996 /* first care about all methods to be flattened into the class */
2997 zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2998
2999 if (aliases) {
3000 efree(aliases);
3001 }
3002
3003 if (exclude_tables) {
3004 efree(exclude_tables);
3005 }
3006
3007 /* then flatten the constants and properties into it, to, mostly to notify developer about problems */
3008 zend_do_traits_constant_binding(ce, traits);
3009 zend_do_traits_property_binding(ce, traits);
3010}
3011/* }}} */
3012
3013#define MAX_ABSTRACT_INFO_CNT 3
3014#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
3015#define DISPLAY_ABSTRACT_FN(idx) \
3016 ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
3017 ai.afn[idx] ? "::" : "", \
3018 ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
3019 ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
3020
3025
3026static void zend_verify_abstract_class_function(const zend_function *fn, zend_abstract_info *ai) /* {{{ */
3027{
3028 if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
3029 ai->afn[ai->cnt] = fn;
3030 }
3031 ai->cnt++;
3032}
3033/* }}} */
3034
3036{
3037 const zend_function *func;
3039 bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
3040 bool can_be_abstract = (ce->ce_flags & ZEND_ACC_ENUM) == 0;
3041 memset(&ai, 0, sizeof(ai));
3042
3044 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
3045 /* If the class is explicitly abstract, we only check private abstract methods,
3046 * because only they must be declared in the same class. */
3047 if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
3048 zend_verify_abstract_class_function(func, &ai);
3049 }
3050 }
3052
3053 if (!is_explicit_abstract) {
3056 if (prop_info->hooks) {
3057 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3058 const zend_function *fn = prop_info->hooks[i];
3059 if (fn && (fn->common.fn_flags & ZEND_ACC_ABSTRACT)) {
3060 zend_verify_abstract_class_function(fn, &ai);
3061 }
3062 }
3063 }
3065 }
3066
3067 if (ai.cnt) {
3068 zend_error_noreturn(E_ERROR, !is_explicit_abstract && can_be_abstract
3069 ? "%s %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
3070 : "%s %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
3071 zend_get_object_type_uc(ce),
3072 ZSTR_VAL(ce->name), ai.cnt,
3073 ai.cnt > 1 ? "s" : "",
3077 );
3078 } else {
3079 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
3081 }
3082}
3083/* }}} */
3084
3119
3120static void variance_obligation_dtor(zval *zv) {
3121 efree(Z_PTR_P(zv));
3122}
3123
3124static void variance_obligation_ht_dtor(zval *zv) {
3127}
3128
3129static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
3130 HashTable *ht;
3132 if (!CG(delayed_variance_obligations)) {
3133 ALLOC_HASHTABLE(CG(delayed_variance_obligations));
3134 zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
3135 }
3136
3137 key = (zend_ulong) (uintptr_t) ce;
3138 ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
3139 if (ht) {
3140 return ht;
3141 }
3142
3144 zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
3145 zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
3147 return ht;
3148}
3149
3150static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
3151 HashTable *obligations = get_or_init_obligations_for_class(ce);
3152 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3153 obligation->type = OBLIGATION_DEPENDENCY;
3154 obligation->dependency_ce = dependency_ce;
3155 zend_hash_next_index_insert_ptr(obligations, obligation);
3156}
3157
3158static void add_compatibility_obligation(
3159 zend_class_entry *ce,
3160 const zend_function *child_fn, zend_class_entry *child_scope,
3161 const zend_function *parent_fn, zend_class_entry *parent_scope) {
3162 HashTable *obligations = get_or_init_obligations_for_class(ce);
3163 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3164 obligation->type = OBLIGATION_COMPATIBILITY;
3165 /* Copy functions, because they may be stack-allocated in the case of traits. */
3166 if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3167 memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
3168 } else {
3169 memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
3170 }
3171 if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
3172 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
3173 } else {
3174 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
3175 }
3176 obligation->child_scope = child_scope;
3177 obligation->parent_scope = parent_scope;
3178 zend_hash_next_index_insert_ptr(obligations, obligation);
3179}
3180
3181static void add_property_compatibility_obligation(
3182 zend_class_entry *ce, const zend_property_info *child_prop,
3183 const zend_property_info *parent_prop, prop_variance variance) {
3184 HashTable *obligations = get_or_init_obligations_for_class(ce);
3185 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3186 obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
3187 obligation->child_prop = child_prop;
3188 obligation->parent_prop = parent_prop;
3189 obligation->variance = variance;
3190 zend_hash_next_index_insert_ptr(obligations, obligation);
3191}
3192
3193static void add_class_constant_compatibility_obligation(
3194 zend_class_entry *ce, const zend_class_constant *child_const,
3195 const zend_class_constant *parent_const, const zend_string *const_name) {
3196 HashTable *obligations = get_or_init_obligations_for_class(ce);
3197 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3198 obligation->type = OBLIGATION_CLASS_CONSTANT_COMPATIBILITY;
3199 obligation->const_name = const_name;
3200 obligation->child_const = child_const;
3201 obligation->parent_const = parent_const;
3202 zend_hash_next_index_insert_ptr(obligations, obligation);
3203}
3204
3205static void add_property_hook_obligation(
3206 zend_class_entry *ce, const zend_property_info *hooked_prop, const zend_function *hook_func) {
3207 HashTable *obligations = get_or_init_obligations_for_class(ce);
3208 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
3209 obligation->type = OBLIGATION_PROPERTY_HOOK;
3210 obligation->hooked_prop = hooked_prop;
3211 obligation->hook_func = hook_func;
3212 zend_hash_next_index_insert_ptr(obligations, obligation);
3213}
3214
3215static void resolve_delayed_variance_obligations(zend_class_entry *ce);
3216
3217static void check_variance_obligation(variance_obligation *obligation) {
3218 if (obligation->type == OBLIGATION_DEPENDENCY) {
3219 zend_class_entry *dependency_ce = obligation->dependency_ce;
3220 if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
3221 zend_class_entry *orig_linking_class = CG(current_linking_class);
3222
3223 CG(current_linking_class) =
3224 (dependency_ce->ce_flags & ZEND_ACC_CACHEABLE) ? dependency_ce : NULL;
3225 resolve_delayed_variance_obligations(dependency_ce);
3226 CG(current_linking_class) = orig_linking_class;
3227 }
3228 } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
3229 inheritance_status status = zend_do_perform_implementation_check(
3230 &obligation->child_fn, obligation->child_scope,
3231 &obligation->parent_fn, obligation->parent_scope);
3233 emit_incompatible_method_error(
3234 &obligation->child_fn, obligation->child_scope,
3235 &obligation->parent_fn, obligation->parent_scope, status);
3236 }
3237 /* Either the compatibility check was successful or only threw a warning. */
3238 } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
3239 verify_property_type_compatibility(obligation->parent_prop, obligation->child_prop, obligation->variance, true, true);
3240 } else if (obligation->type == OBLIGATION_CLASS_CONSTANT_COMPATIBILITY) {
3242 class_constant_types_compatible(obligation->parent_const, obligation->child_const);
3243 if (status != INHERITANCE_SUCCESS) {
3244 emit_incompatible_class_constant_error(obligation->child_const, obligation->parent_const, obligation->const_name);
3245 }
3246 } else if (obligation->type == OBLIGATION_PROPERTY_HOOK) {
3248 if (status != INHERITANCE_SUCCESS) {
3250 }
3251 } else {
3253 }
3254}
3255
3256static void load_delayed_classes(zend_class_entry *ce) {
3257 HashTable *delayed_autoloads = CG(delayed_autoloads);
3258 if (!delayed_autoloads) {
3259 return;
3260 }
3261
3262 /* Autoloading can trigger linking of another class, which may register new delayed autoloads.
3263 * For that reason, this code uses a loop that pops and loads the first element of the HT. If
3264 * this triggers linking, then the remaining classes may get loaded when linking the newly
3265 * loaded class. This is important, as otherwise necessary dependencies may not be available
3266 * if the new class is lower in the hierarchy than the current one. */
3267 HashPosition pos = 0;
3269 zend_ulong idx;
3270 while (zend_hash_get_current_key_ex(delayed_autoloads, &name, &idx, &pos)
3272 zend_string_addref(name);
3273 zend_hash_del(delayed_autoloads, name);
3275 zend_string_release(name);
3276 if (EG(exception)) {
3278 "During inheritance of %s, while autoloading %s",
3279 ZSTR_VAL(ce->name), ZSTR_VAL(name));
3280 }
3281 }
3282}
3283
3284static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
3285 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
3286 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
3287
3288 ZEND_ASSERT(all_obligations != NULL);
3289 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
3290 ZEND_ASSERT(obligations != NULL);
3291
3292 variance_obligation *obligation;
3293 ZEND_HASH_FOREACH_PTR(obligations, obligation) {
3294 check_variance_obligation(obligation);
3296
3298
3301 zend_hash_index_del(all_obligations, num_key);
3302}
3303
3304static void check_unrecoverable_load_failure(const zend_class_entry *ce) {
3305 /* If this class has been used while unlinked through a variance obligation, it is not legal
3306 * to remove the class from the class table and throw an exception, because there is already
3307 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
3308 * a fatal error, as would happen if we did not allow exceptions in the first place. */
3309 if (CG(unlinked_uses)
3310 && zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t)ce) == SUCCESS) {
3312 "During inheritance of %s with variance dependencies", ZSTR_VAL(ce->name));
3313 }
3314}
3315
3316#define zend_update_inherited_handler(handler) do { \
3317 if (ce->handler == (zend_function*)op_array) { \
3318 ce->handler = (zend_function*)new_op_array; \
3319 } \
3320 } while (0)
3321
3322static zend_op_array *zend_lazy_method_load(
3323 zend_op_array *op_array, zend_class_entry *ce, const zend_class_entry *pce) {
3324 ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
3325 ZEND_ASSERT(op_array->scope == pce);
3326 ZEND_ASSERT(op_array->prototype == NULL);
3327 zend_op_array *new_op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
3328 memcpy(new_op_array, op_array, sizeof(zend_op_array));
3329 new_op_array->fn_flags &= ~ZEND_ACC_IMMUTABLE;
3330 new_op_array->scope = ce;
3331 ZEND_MAP_PTR_INIT(new_op_array->run_time_cache, NULL);
3332 ZEND_MAP_PTR_INIT(new_op_array->static_variables_ptr, NULL);
3333
3334 return new_op_array;
3335}
3336
3337static zend_class_entry *zend_lazy_class_load(zend_class_entry *pce)
3338{
3339 zend_class_entry *ce;
3340 Bucket *p, *end;
3341
3342 ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
3343 memcpy(ce, pce, sizeof(zend_class_entry));
3345 ce->refcount = 1;
3346 ce->inheritance_cache = NULL;
3347 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3348 ZEND_MAP_PTR_NEW(ce->mutable_data);
3349 } else {
3350 ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
3351 }
3352
3353 /* properties */
3354 if (ce->default_properties_table) {
3355 zval *dst = emalloc(sizeof(zval) * ce->default_properties_count);
3356 zval *src = ce->default_properties_table;
3357 zval *end = src + ce->default_properties_count;
3358
3359 ce->default_properties_table = dst;
3360 for (; src != end; src++, dst++) {
3361 ZVAL_COPY_VALUE_PROP(dst, src);
3362 }
3363 }
3364
3365 /* methods */
3371 p = ce->function_table.arData;
3372 end = p + ce->function_table.nNumUsed;
3373 for (; p != end; p++) {
3374 zend_op_array *op_array = Z_PTR(p->val);
3375 zend_op_array *new_op_array = Z_PTR(p->val) = zend_lazy_method_load(op_array, ce, pce);
3376
3377 zend_update_inherited_handler(constructor);
3386 zend_update_inherited_handler(__callstatic);
3387 zend_update_inherited_handler(__debugInfo);
3388 zend_update_inherited_handler(__serialize);
3389 zend_update_inherited_handler(__unserialize);
3390 }
3391 }
3392
3393 /* static members */
3395 zval *dst = emalloc(sizeof(zval) * ce->default_static_members_count);
3398
3400 for (; src != end; src++, dst++) {
3401 ZVAL_COPY_VALUE(dst, src);
3402 }
3403 }
3404 ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
3405
3406 /* properties_info */
3411 p = ce->properties_info.arData;
3412 end = p + ce->properties_info.nNumUsed;
3413 for (; p != end; p++) {
3414 zend_property_info *prop_info, *new_prop_info;
3415
3416 prop_info = Z_PTR(p->val);
3417 ZEND_ASSERT(prop_info->ce == pce);
3418 ZEND_ASSERT(prop_info->prototype == prop_info);
3419 new_prop_info= zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
3420 Z_PTR(p->val) = new_prop_info;
3421 memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
3422 new_prop_info->ce = ce;
3423 new_prop_info->prototype = new_prop_info;
3424 /* Deep copy the type information */
3425 zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
3426 if (new_prop_info->hooks) {
3427 new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3428 memcpy(new_prop_info->hooks, prop_info->hooks, ZEND_PROPERTY_HOOK_STRUCT_SIZE);
3429 for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
3430 if (new_prop_info->hooks[i]) {
3431 zend_op_array *hook = zend_lazy_method_load((zend_op_array *) new_prop_info->hooks[i], ce, pce);
3433 hook->prop_info = new_prop_info;
3434 new_prop_info->ce = ce;
3435 new_prop_info->hooks[i] = (zend_function *) hook;
3436 }
3437 }
3438 }
3439 }
3440 }
3441
3442 /* constants table */
3447 p = ce->constants_table.arData;
3448 end = p + ce->constants_table.nNumUsed;
3449 for (; p != end; p++) {
3450 zend_class_constant *c, *new_c;
3451
3452 c = Z_PTR(p->val);
3453 ZEND_ASSERT(c->ce == pce);
3454 new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
3455 Z_PTR(p->val) = new_c;
3456 memcpy(new_c, c, sizeof(zend_class_constant));
3457 new_c->ce = ce;
3458 }
3459 }
3460
3461 return ce;
3462}
3463
3464#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
3465# define UPDATE_IS_CACHEABLE(ce) do { \
3466 if ((ce)->type == ZEND_USER_CLASS) { \
3467 is_cacheable &= (ce)->ce_flags; \
3468 } \
3469 } while (0)
3470#else
3471// TODO: ASLR may cause different addresses in different workers ???
3472# define UPDATE_IS_CACHEABLE(ce) do { \
3473 is_cacheable &= (ce)->ce_flags; \
3474 } while (0)
3475#endif
3476
3478{
3479 /* Load parent/interface dependencies first, so we can still gracefully abort linking
3480 * with an exception and remove the class from the class table. This is only possible
3481 * if no variance obligations on the current class have been added during autoloading. */
3482 zend_class_entry *parent = NULL;
3483 zend_class_entry **traits_and_interfaces = NULL;
3484 zend_class_entry *proto = NULL;
3485 zend_class_entry *orig_linking_class;
3486 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3487 uint32_t i, j;
3488 zval *zv;
3489 ALLOCA_FLAG(use_heap)
3490
3491 SET_ALLOCA_FLAG(use_heap);
3493
3494 if (ce->parent_name) {
3495 parent = zend_fetch_class_by_name(
3496 ce->parent_name, lc_parent_name,
3498 if (!parent) {
3499 check_unrecoverable_load_failure(ce);
3500 return NULL;
3501 }
3502 UPDATE_IS_CACHEABLE(parent);
3503 }
3504
3505 if (ce->num_traits || ce->num_interfaces) {
3506 traits_and_interfaces = do_alloca(sizeof(zend_class_entry*) * (ce->num_traits + ce->num_interfaces), use_heap);
3507
3508 for (i = 0; i < ce->num_traits; i++) {
3511 if (UNEXPECTED(trait == NULL)) {
3512 free_alloca(traits_and_interfaces, use_heap);
3513 return NULL;
3514 }
3515 if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
3516 zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
3517 free_alloca(traits_and_interfaces, use_heap);
3518 return NULL;
3519 }
3520 for (j = 0; j < i; j++) {
3521 if (traits_and_interfaces[j] == trait) {
3522 /* skip duplications */
3523 trait = NULL;
3524 break;
3525 }
3526 }
3527 traits_and_interfaces[i] = trait;
3528 if (trait) {
3529 UPDATE_IS_CACHEABLE(trait);
3530 }
3531 }
3532 }
3533
3534 if (ce->num_interfaces) {
3535 for (i = 0; i < ce->num_interfaces; i++) {
3540 if (!iface) {
3541 check_unrecoverable_load_failure(ce);
3542 free_alloca(traits_and_interfaces, use_heap);
3543 return NULL;
3544 }
3545 traits_and_interfaces[ce->num_traits + i] = iface;
3546 if (iface) {
3547 UPDATE_IS_CACHEABLE(iface);
3548 }
3549 }
3550 }
3551
3552#ifndef ZEND_WIN32
3553 if (ce->ce_flags & ZEND_ACC_ENUM) {
3554 /* We will add internal methods. */
3555 is_cacheable = false;
3556 }
3557#endif
3558
3559 bool orig_record_errors = EG(record_errors);
3560
3561 if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
3563 zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
3564 if (ret) {
3565 if (traits_and_interfaces) {
3566 free_alloca(traits_and_interfaces, use_heap);
3567 }
3568 zv = zend_hash_find_known_hash(CG(class_table), key);
3569 Z_CE_P(zv) = ret;
3570 return ret;
3571 }
3572
3573 /* Make sure warnings (such as deprecations) thrown during inheritance
3574 * will be recorded in the inheritance cache. */
3576 } else {
3577 is_cacheable = 0;
3578 }
3579 proto = ce;
3580 }
3581
3582 zend_try {
3583 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3584 /* Lazy class loading */
3585 ce = zend_lazy_class_load(ce);
3586 zv = zend_hash_find_known_hash(CG(class_table), key);
3587 Z_CE_P(zv) = ce;
3588 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3589 /* Lazy class loading */
3590 ce = zend_lazy_class_load(ce);
3592 zv = zend_hash_find_known_hash(CG(class_table), key);
3593 Z_CE_P(zv) = ce;
3594 }
3595
3596 if (CG(unlinked_uses)) {
3597 zend_hash_index_del(CG(unlinked_uses), (zend_long)(uintptr_t) ce);
3598 }
3599
3600 orig_linking_class = CG(current_linking_class);
3601 CG(current_linking_class) = is_cacheable ? ce : NULL;
3602
3603 if (ce->ce_flags & ZEND_ACC_ENUM) {
3604 /* Only register builtin enum methods during inheritance to avoid persisting them in
3605 * opcache. */
3607 }
3608
3609#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3610 zend_link_hooked_object_iter(ce);
3611#endif
3612
3613 if (parent) {
3614 if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
3615 add_dependency_obligation(ce, parent);
3616 }
3617 zend_do_inheritance(ce, parent);
3618 }
3619 if (ce->num_traits) {
3620 zend_do_bind_traits(ce, traits_and_interfaces);
3621 }
3622 if (ce->num_interfaces) {
3623 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
3624 uint32_t num_parent_interfaces = parent ? parent->num_interfaces : 0;
3625 zend_class_entry **interfaces = emalloc(
3626 sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
3627
3628 if (num_parent_interfaces) {
3629 memcpy(interfaces, parent->interfaces,
3630 sizeof(zend_class_entry *) * num_parent_interfaces);
3631 }
3632 memcpy(interfaces + num_parent_interfaces, traits_and_interfaces + ce->num_traits,
3633 sizeof(zend_class_entry *) * ce->num_interfaces);
3634
3635 zend_do_implement_interfaces(ce, interfaces);
3636 } else if (parent && parent->num_interfaces) {
3637 zend_do_inherit_interfaces(ce, parent);
3638 }
3641 ) {
3643 }
3644 if (ce->ce_flags & ZEND_ACC_ENUM) {
3645 zend_verify_enum(ce);
3646 }
3650 if (prop_info->ce == ce && prop_info->hooks && prop_info->hooks[ZEND_PROPERTY_HOOK_SET]) {
3653 break;
3654 case INHERITANCE_ERROR:
3656 break;
3658 add_property_hook_obligation(ce, prop_info, prop_info->hooks[ZEND_PROPERTY_HOOK_SET]);
3659 break;
3662 }
3663 }
3665 }
3666
3667 /* Normally Stringable is added during compilation. However, if it is imported from a trait,
3668 * we need to explicitly add the interface here. */
3669 if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
3673 ce->num_interfaces++;
3677 do_interface_implementation(ce, zend_ce_stringable);
3678 }
3679
3681 } zend_catch {
3682 /* Do not leak recorded errors to the next linked class. */
3683 if (!orig_record_errors) {
3684 EG(record_errors) = false;
3686 }
3687 zend_bailout();
3688 } zend_end_try();
3689
3690 EG(record_errors) = orig_record_errors;
3691
3695 } else {
3697 if (CG(current_linking_class)) {
3699 }
3700 load_delayed_classes(ce);
3702 resolve_delayed_variance_obligations(ce);
3703 }
3704 if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
3706 } else {
3707 CG(current_linking_class) = NULL;
3708 }
3709 }
3710
3711 if (!CG(current_linking_class)) {
3712 is_cacheable = 0;
3713 }
3714 CG(current_linking_class) = orig_linking_class;
3715
3716 if (is_cacheable) {
3718 zend_class_entry *new_ce;
3719
3720 ce->inheritance_cache = NULL;
3721 new_ce = zend_inheritance_cache_add(ce, proto, parent, traits_and_interfaces, ht);
3722 if (new_ce) {
3723 zv = zend_hash_find_known_hash(CG(class_table), key);
3724 ce = new_ce;
3725 Z_CE_P(zv) = ce;
3726 }
3727 if (ht) {
3730 }
3731 }
3732
3733 if (!orig_record_errors) {
3735 }
3736 if (traits_and_interfaces) {
3737 free_alloca(traits_and_interfaces, use_heap);
3738 }
3739
3740 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3741 ZSTR_SET_CE_CACHE(ce->name, ce);
3742 }
3743
3744 return ce;
3745}
3746/* }}} */
3747
3748/* Check whether early binding is prevented due to unresolved types in inheritance checks. */
3749static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
3750{
3752 zend_function *parent_func;
3753 const zend_property_info *parent_info;
3754 const zend_class_constant *parent_const;
3755 inheritance_status overall_status = INHERITANCE_SUCCESS;
3756
3757 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
3759 if (zv) {
3760 zend_function *child_func = Z_FUNC_P(zv);
3762 do_inheritance_check_on_method(
3763 child_func, child_func->common.scope,
3764 parent_func, parent_func->common.scope,
3765 ce, NULL,
3768 overall_status = INHERITANCE_WARNING;
3769 } else if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
3770 return status;
3771 }
3772 }
3774
3775 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
3776 const zval *zv;
3777 if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
3778 continue;
3779 }
3780
3782 if (zv) {
3783 const zend_property_info *child_info = Z_PTR_P(zv);
3784 if (ZEND_TYPE_IS_SET(child_info->type)) {
3785 inheritance_status status = verify_property_type_compatibility(parent_info, child_info, prop_get_variance(parent_info), false, false);
3787 return status;
3788 }
3789 }
3790 }
3792
3793 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, parent_const) {
3794 const zval *zv;
3795 if ((ZEND_CLASS_CONST_FLAGS(parent_const) & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_const->type)) {
3796 continue;
3797 }
3798
3800 if (zv) {
3801 const zend_class_constant *child_const = Z_PTR_P(zv);
3802 if (ZEND_TYPE_IS_SET(child_const->type)) {
3803 inheritance_status status = class_constant_types_compatible(parent_const, child_const);
3806 return status;
3807 }
3808 }
3809 }
3811
3812 return overall_status;
3813}
3814/* }}} */
3815
3816static zend_always_inline bool register_early_bound_ce(zval *delayed_early_binding, zend_string *lcname, zend_class_entry *ce) {
3817 if (delayed_early_binding) {
3818 if (EXPECTED(!(ce->ce_flags & ZEND_ACC_PRELOADED))) {
3819 if (zend_hash_set_bucket_key(EG(class_table), (Bucket *)delayed_early_binding, lcname) != NULL) {
3820 Z_CE_P(delayed_early_binding) = ce;
3821 return true;
3822 }
3823 } else {
3824 /* If preloading is used, don't replace the existing bucket, add a new one. */
3825 if (zend_hash_add_ptr(EG(class_table), lcname, ce) != NULL) {
3826 return true;
3827 }
3828 }
3829 zend_class_entry *old_ce = zend_hash_find_ptr(EG(class_table), lcname);
3830 ZEND_ASSERT(old_ce);
3832 return false;
3833 }
3834 if (zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL) {
3835 return true;
3836 }
3837 return false;
3838}
3839
3841{
3843 zend_class_entry *proto = NULL;
3844 zend_class_entry *orig_linking_class;
3845
3846 if (ce->ce_flags & ZEND_ACC_LINKED) {
3847 ZEND_ASSERT(ce->parent == NULL);
3848 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3849 return NULL;
3850 }
3851 zend_observer_class_linked_notify(ce, lcname);
3852 return ce;
3853 }
3854
3855 uint32_t is_cacheable = ce->ce_flags & ZEND_ACC_IMMUTABLE;
3856 UPDATE_IS_CACHEABLE(parent_ce);
3857 if (is_cacheable) {
3860 if (ret) {
3861 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ret))) {
3862 return NULL;
3863 }
3864 zend_observer_class_linked_notify(ret, lcname);
3865 return ret;
3866 }
3867 } else {
3868 is_cacheable = 0;
3869 }
3870 proto = ce;
3871 }
3872
3873 orig_linking_class = CG(current_linking_class);
3874 CG(current_linking_class) = NULL;
3875 status = zend_can_early_bind(ce, parent_ce);
3876 CG(current_linking_class) = orig_linking_class;
3878 if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
3879 /* Lazy class loading */
3880 ce = zend_lazy_class_load(ce);
3881 } else if (ce->ce_flags & ZEND_ACC_FILE_CACHED) {
3882 /* Lazy class loading */
3883 ce = zend_lazy_class_load(ce);
3885 }
3886
3887 if (UNEXPECTED(!register_early_bound_ce(delayed_early_binding, lcname, ce))) {
3888 return NULL;
3889 }
3890
3891 orig_linking_class = CG(current_linking_class);
3892 CG(current_linking_class) = is_cacheable ? ce : NULL;
3893
3894 zend_try{
3895 CG(zend_lineno) = ce->info.user.line_start;
3896
3897 if (is_cacheable) {
3899 }
3900
3901#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
3902 zend_link_hooked_object_iter(ce);
3903#endif
3904
3906 if (parent_ce && parent_ce->num_interfaces) {
3907 zend_do_inherit_interfaces(ce, parent_ce);
3908 }
3912 }
3916
3917 CG(current_linking_class) = orig_linking_class;
3918 } zend_catch {
3919 EG(record_errors) = false;
3921 zend_bailout();
3922 } zend_end_try();
3923
3924 EG(record_errors) = false;
3925
3926 if (is_cacheable) {
3928 zend_class_entry *new_ce;
3929
3930 ce->inheritance_cache = NULL;
3931 new_ce = zend_inheritance_cache_add(ce, proto, parent_ce, NULL, ht);
3932 if (new_ce) {
3933 zval *zv = zend_hash_find_known_hash(CG(class_table), lcname);
3934 ce = new_ce;
3935 Z_CE_P(zv) = ce;
3936 }
3937 if (ht) {
3940 }
3941 }
3942
3943 if (ZSTR_HAS_CE_CACHE(ce->name)) {
3944 ZSTR_SET_CE_CACHE(ce->name, ce);
3945 }
3946 zend_observer_class_linked_notify(ce, lcname);
3947
3948 return ce;
3949 }
3950 return NULL;
3951}
3952/* }}} */
bool exception
Definition assert.c:30
constant(string $name)
DNS_STATUS status
Definition dns_win32.c:49
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
new_type size
Definition ffi.c:4365
new_type kind
Definition ffi.c:4363
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
HashTable * ht
Definition ffi.c:4838
ffi persistent
Definition ffi.c:3633
#define NULL
Definition gdcache.h:45
#define prefix
#define SUCCESS
Definition hash_sha3.c:261
again j
#define memmove(a, b, c)
char * arena
Definition php_bcmath.h:37
unsigned const char * end
Definition php_ffi.h:51
unsigned const char * pos
Definition php_ffi.h:52
php_output_handler * active
Definition php_output.h:140
unsigned char key[REFLECTION_KEY_LEN]
zend_string * lcname
p
Definition session.c:1105
const zend_function * afn[MAX_ABSTRACT_INFO_CNT+1]
zend_string * name
uint32_t nNumUsed
Definition zend_types.h:406
dtor_func_t pDestructor
Definition zend_types.h:411
Bucket * arData
Definition zend_types.h:403
zend_ast_kind kind
Definition zend_ast.h:187
zend_ast * child[1]
Definition zend_ast.h:190
zend_class_entry * ce
HashTable constants_table
Definition zend.h:165
zend_function * __debugInfo
Definition zend.h:182
zend_object *(* create_object)(zend_class_entry *class_type)
Definition zend.h:195
zend_function * __set
Definition zend.h:176
zend_function * __tostring
Definition zend.h:181
struct _zend_module_entry * module
Definition zend.h:234
zval * default_static_members_table
Definition zend.h:161
struct _zend_class_entry::@126215362204241324314155352336150042254204116267::@166057154351252324007362117353350250255142166322 user
uint32_t num_hooked_props
Definition zend.h:207
HashTable properties_info
Definition zend.h:164
zend_function * __isset
Definition zend.h:178
zend_trait_precedence ** trait_precedences
Definition zend.h:218
zend_object_iterator *(* get_iterator)(zend_class_entry *ce, zval *object, int by_ref)
Definition zend.h:198
zend_string * filename
Definition zend.h:228
zend_class_name * trait_names
Definition zend.h:216
zend_class_name * interface_names
Definition zend.h:213
zend_function * __unserialize
Definition zend.h:184
zend_string * name
Definition zend.h:149
union _zend_class_entry::@126215362204241324314155352336150042254204116267 info
zend_function * __call
Definition zend.h:179
uint32_t num_traits
Definition zend.h:206
struct _zend_class_entry::@126215362204241324314155352336150042254204116267::@031207115026352130035014265255253014334154061307 internal
uint32_t num_interfaces
Definition zend.h:205
zend_function * __unset
Definition zend.h:177
zend_string * parent_name
Definition zend.h:153
uint32_t ce_flags
Definition zend.h:156
int default_properties_count
Definition zend.h:158
zend_function * __serialize
Definition zend.h:183
char type
Definition zend.h:148
uint32_t line_start
Definition zend.h:229
zend_trait_alias ** trait_aliases
Definition zend.h:217
zend_class_entry ** interfaces
Definition zend.h:212
zend_function * __get
Definition zend.h:175
int default_static_members_count
Definition zend.h:159
int(* interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type)
Definition zend.h:196
int refcount
Definition zend.h:155
zend_function * constructor
Definition zend.h:172
uint32_t num_hooked_prop_variance_checks
Definition zend.h:208
zend_inheritance_cache_entry * inheritance_cache
Definition zend.h:168
struct _zend_property_info ** properties_info_table
Definition zend.h:170
zend_class_entry * parent
Definition zend.h:152
int(* serialize)(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
Definition zend.h:202
zval * default_properties_table
Definition zend.h:160
HashTable function_table
Definition zend.h:163
int(* unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
Definition zend.h:203
const zend_object_handlers * default_object_handlers
Definition zend.h:186
zend_function * __callstatic
Definition zend.h:180
zend_function * clone
Definition zend.h:174
zend_function * destructor
Definition zend.h:173
zend_string * lc_name
Definition zend.h:87
zend_string * name
Definition zend.h:86
unsigned char type
zend_function * prototype
HashTable * static_variables
const zend_property_info * prop_info
zend_string * filename
uint32_t line_start
zend_class_entry * scope
zend_op * opcodes
uint32_t fn_flags
znode_op op1
znode_op op2
uint8_t opcode
uint8_t op2_type
const zend_property_info * prototype
zend_string * doc_comment
zend_function ** hooks
zend_string * name
HashTable * attributes
zend_class_entry * ce
zend_trait_method_reference trait_method
Definition zend.h:102
uint32_t modifiers
Definition zend.h:112
zend_string * alias
Definition zend.h:107
zend_string * method_name
Definition zend.h:91
zend_string * class_name
Definition zend.h:92
zend_trait_method_reference trait_method
Definition zend.h:96
zend_string * exclude_class_names[1]
Definition zend.h:98
uint32_t num_excludes
Definition zend.h:97
zend_string * s
const zend_property_info * child_prop
const zend_class_constant * parent_const
const zend_property_info * hooked_prop
zend_class_entry * dependency_ce
enum variance_obligation::@330322236061147115211222154203135051132232375075 type
const zend_property_info * parent_prop
zend_class_entry * parent_scope
const zend_string * const_name
zend_class_entry * child_scope
const zend_class_constant * child_const
const zend_function * hook_func
uint32_t num_types
Definition zend_types.h:141
zend_arg_info * arg_info
zend_function * prototype
uint32_t required_num_args
zend_class_entry * scope
zend_op_array op_array
const zend_property_info * prop_info
zend_string * function_name
struct _zend_function::@236135173067030250234125302313220025134003177336 common
HashTable * attributes
uint32_t fn_flags
uint32_t num_args
uint32_t num
ZEND_API ZEND_COLD void zend_error_at(int type, zend_string *filename, uint32_t lineno, const char *format,...)
Definition zend.c:1642
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format,...)
Definition zend.c:1703
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_at_noreturn(int type, zend_string *filename, uint32_t lineno, const char *format,...)
Definition zend.c:1674
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
ZEND_API void zend_free_recorded_errors(void)
Definition zend.c:1755
ZEND_API void zend_begin_record_errors(void)
Definition zend.c:1738
struct _zend_inheritance_cache_entry zend_inheritance_cache_entry
Definition zend.h:127
struct _zend_trait_precedence zend_trait_precedence
#define zend_catch
Definition zend.h:277
struct _zend_trait_alias zend_trait_alias
#define zend_try
Definition zend.h:270
#define zend_end_try()
Definition zend.h:280
#define zend_bailout()
Definition zend.h:268
struct _zend_trait_method_reference zend_trait_method_reference
ZEND_API ZEND_COLD const char * zend_get_object_type_case(const zend_class_entry *ce, bool upper_case)
Definition zend_API.c:5260
ZEND_API zend_property_info * zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type)
Definition zend_API.c:4505
ZEND_API ZEND_COLD void zend_class_redeclaration_error(int type, zend_class_entry *old_ce)
Definition zend_API.c:463
ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, zend_string *lcname)
Definition zend_API.c:2859
#define perealloc(ptr, size, persistent)
Definition zend_alloc.h:201
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define pefree(ptr, persistent)
Definition zend_alloc.h:191
#define pemalloc(size, persistent)
Definition zend_alloc.h:189
#define FREE_HASHTABLE(ht)
Definition zend_alloc.h:234
#define erealloc(ptr, size)
Definition zend_alloc.h:159
#define ALLOC_HASHTABLE(ht)
Definition zend_alloc.h:231
#define emalloc(size)
Definition zend_alloc.h:151
@ ZEND_AST_CONSTANT
Definition zend_ast.h:37
@ ZEND_AST_CLASS_CONST
Definition zend_ast.h:120
ZEND_API zend_attribute * zend_get_attribute_str(HashTable *attributes, const char *str, size_t len)
struct _zend_attribute zend_attribute
struct _zval_struct zval
uint32_t num_args
zend_string_release_ex(func->internal_function.function_name, 0)
execute_data func
zend_string * zend_type_to_string_resolved(zend_type type, zend_class_entry *scope)
ZEND_API void function_add_ref(zend_function *function)
#define ZEND_PROPERTY_HOOK_COUNT
#define ZEND_ACC_UNRESOLVED_VARIANCE
#define ZEND_ACC_ENUM
struct _zend_op zend_op
#define OBJ_PROP_TO_NUM(offset)
#define ZEND_USER_CODE(type)
#define IS_UNUSED
#define ZEND_ACC_FINAL
#define ZEND_ACC_CACHEABLE
#define ZEND_ACC_IMMUTABLE
#define ZEND_ACC_NOT_SERIALIZABLE
#define ZEND_ACC_CACHED
#define ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED
#define ZEND_COMPILE_PRELOAD
#define ZEND_HAS_STATIC_IN_METHODS
#define ZEND_ACC_HAS_TYPE_HINTS
#define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS
#define ZEND_ACC_CTOR
#define ZEND_INTERNAL_FUNCTION
#define ZEND_ACC_ABSTRACT
#define ZEND_ACC_HAS_READONLY_PROPS
#define ZEND_CLASS_CONST_FLAGS(c)
#define ZEND_ACC_LINKED
#define ZEND_ACC_TRAIT_CLONE
#define ZEND_ACC_READONLY
#define ZEND_ACC_PROTECTED_SET
#define ZEND_ACC_CHANGED
#define ZEND_ARG_SEND_MODE(arg_info)
#define ZEND_FETCH_CLASS_TRAIT
#define ZEND_ACC_PPP_SET_MASK
#define ZEND_COMPILE_IGNORE_OTHER_FILES
#define ZEND_ACC_NEARLY_LINKED
#define ZEND_FUNCTION_DTOR
#define ZEND_FETCH_CLASS_INTERFACE
#define ZEND_FETCH_CLASS_NO_AUTOLOAD
#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
#define ZEND_USER_FUNCTION
#define ZEND_ACC_INTERFACE
#define ZEND_ACC_PRIVATE_SET
#define ZEND_ACC_HAS_AST_CONSTANTS
struct _zend_op_array zend_op_array
#define ZEND_ACC_READONLY_CLASS
#define ZEND_PROPERTY_HOOK_STRUCT_SIZE
struct _zend_class_constant zend_class_constant
struct _zend_property_info zend_property_info
#define ZEND_ACC_HAS_AST_PROPERTIES
#define ZEND_ACC_TRAIT
#define ZEND_ACC_RESOLVED_PARENT
#define ZEND_COMPILE_IGNORE_INTERNAL_CLASSES
#define ZEND_ACC_PRELOADED
#define ZEND_VIRTUAL_PROPERTY_OFFSET
#define ZEND_ACC_USE_GUARDS
#define ZEND_ACC_PRIVATE
#define ZEND_ARG_TYPE_IS_TENTATIVE(arg_info)
#define ZEND_ACC_CONSTANTS_UPDATED
struct _zend_internal_arg_info zend_internal_arg_info
#define ZEND_ACC_ANON_CLASS
#define ZEND_ACC_HAS_AST_STATICS
#define ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
#define RT_CONSTANT(opline, node)
#define ZEND_ACC_PPP_MASK
#define ZEND_ACC_STATIC
#define ZEND_ARG_IS_VARIADIC(arg_info)
#define ZEND_FETCH_CLASS_EXCEPTION
#define ZEND_ACC_PUBLIC
#define ZEND_ACC_HAS_RETURN_TYPE
struct _zend_arg_info zend_arg_info
#define ZEND_ACC_PUBLIC_SET
#define ZEND_ACC_FILE_CACHED
#define ZEND_ACC_RESOLVED_INTERFACES
#define ZEND_ACC_ARENA_ALLOCATED
#define ZEND_ACC_VIRTUAL
#define ZEND_ACC_VARIADIC
#define ZEND_USER_CLASS
#define ZEND_FETCH_CLASS_ALLOW_UNLINKED
#define OBJ_PROP_TO_OFFSET(num)
#define ZEND_ACC_OVERRIDE
#define ZEND_INTERNAL_CLASS
#define ZEND_CONSTRUCTOR_FUNC_NAME
struct _zend_internal_function zend_internal_function
#define ZEND_ACC_RETURN_REFERENCE
char * zend_visibility_string(uint32_t fn_flags)
#define ZEND_FN_SCOPE_NAME(function)
#define ZEND_ACC_PROTECTED
#define ZEND_API
#define CONST_OWNED
void zend_verify_enum(const zend_class_entry *ce)
Definition zend_enum.c:120
void zend_enum_register_funcs(zend_class_entry *ce)
Definition zend_enum.c:439
#define E_COMPILE_ERROR
Definition zend_errors.h:29
#define E_ERROR
Definition zend_errors.h:23
#define E_CORE_ERROR
Definition zend_errors.h:27
#define E_DEPRECATED
Definition zend_errors.h:37
#define E_COMPILE_WARNING
Definition zend_errors.h:30
ZEND_NORETURN void zend_exception_uncaught_error(const char *format,...)
ZEND_API zend_class_entry * zend_lookup_class(zend_string *name)
ZEND_API zend_class_entry * zend_fetch_class_by_name(zend_string *class_name, zend_string *lcname, uint32_t fetch_type)
ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope)
ZEND_API zend_class_entry * zend_lookup_class_ex(zend_string *name, zend_string *lcname, uint32_t flags)
union _zend_function zend_function
#define CG(v)
#define EG(v)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_set_bucket_key(HashTable *ht, Bucket *b, zend_string *key)
Definition zend_hash.c:1239
ZEND_API int ZEND_FASTCALL zend_hash_get_current_key_ex(const HashTable *ht, zend_string **str_index, zend_ulong *num_index, const HashPosition *pos)
Definition zend_hash.c:2846
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1692
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
ZEND_API void ZEND_FASTCALL zend_hash_extend(HashTable *ht, uint32_t nSize, bool packed)
Definition zend_hash.c:396
ZEND_API zval *ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
Definition zend_hash.c:1067
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
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define HASH_KEY_NON_EXISTENT
Definition zend_hash.h:31
#define ZEND_HASH_FOREACH_STR_KEY_PTR(ht, _key, _ptr)
Definition zend_hash.h:1225
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define ZEND_HASH_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1118
#define HASH_FLAG_UNINITIALIZED
Definition zend_hash.h:42
#define ZEND_HASH_MAP_FOREACH_STR_KEY(ht, _key)
Definition zend_hash.h:1346
#define ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(ht, _key, _ptr)
Definition zend_hash.h:1433
#define HT_FLAGS(ht)
Definition zend_hash.h:50
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
ZEND_API zend_class_entry * zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding)
ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface)
#define MAX_ABSTRACT_INFO_CNT
prop_variance
@ PROP_COVARIANT
@ PROP_CONTRAVARIANT
@ PROP_INVARIANT
#define ZEND_INHERITANCE_CHECK_PROTO
#define ZEND_INHERITANCE_LAZY_CHILD_CLONE
void zend_inheritance_check_override(zend_class_entry *ce)
struct _zend_abstract_info zend_abstract_info
ZEND_API inheritance_status zend_perform_covariant_type_check(zend_class_entry *fe_scope, zend_type fe_type, zend_class_entry *proto_scope, zend_type proto_type)
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error(const zend_property_info *prop_info)
void zend_build_properties_info_table(zend_class_entry *ce)
ZEND_API zend_class_entry *(* zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
zend_inheritance_status inheritance_status
#define SEPARATE_METHOD()
#define ZEND_INHERITANCE_RESET_CHILD_OVERRIDE
ZEND_API void zend_verify_hooked_property(zend_class_entry *ce, zend_property_info *prop_info, zend_string *prop_name)
ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, bool checked)
ZEND_API zend_class_entry * zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name, zend_string *key)
#define ZEND_INHERITANCE_CHECK_VISIBILITY
ZEND_API zend_class_entry *(* zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces)
#define ZEND_INHERITANCE_SET_CHILD_CHANGED
#define MAX_ABSTRACT_INFO_FMT
#define ZEND_INHERITANCE_SET_CHILD_PROTO
#define DISPLAY_ABSTRACT_FN(idx)
ZEND_API inheritance_status zend_verify_property_hook_variance(const zend_property_info *prop_info, const zend_function *func)
ZEND_API ZEND_COLD ZEND_NORETURN void zend_hooked_property_variance_error_ex(zend_string *value_param_name, zend_string *class_name, zend_string *prop_name)
#define zend_update_inherited_handler(handler)
#define ZEND_INHERITANCE_CHECK_SILENT
void zend_verify_abstract_class(zend_class_entry *ce)
#define UPDATE_IS_CACHEABLE(ce)
char * zend_visibility_string(uint32_t fn_flags)
zend_inheritance_status
@ INHERITANCE_ERROR
@ INHERITANCE_WARNING
@ INHERITANCE_SUCCESS
@ INHERITANCE_UNRESOLVED
ZEND_API zend_class_entry * zend_ce_stringable
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
struct _zend_string zend_string
#define ZEND_MAP_PTR_INIT(ptr, val)
#define ZEND_MAP_PTR_NEW(ptr)
#define ZEND_MAP_PTR(ptr)
#define MODULE_PERSISTENT
ZEND_API bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce)
#define ALLOCA_FLAG(name)
#define MIN(a, b)
#define EXPECTED(condition)
#define do_alloca(p, use_heap)
#define zend_always_inline
#define ZEND_ASSERT(c)
#define ZEND_UNREACHABLE()
#define free_alloca(p, use_heap)
#define ZEND_COLD
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
#define ZEND_NORETURN
#define SET_ALLOCA_FLAG(name)
#define MAX(a, b)
ZEND_API zend_object_iterator * zend_hooked_object_get_iterator(zend_class_entry *ce, zval *object, int by_ref)
zend_property_hook_kind
@ ZEND_PROPERTY_HOOK_SET
@ ZEND_PROPERTY_HOOK_GET
struct _zend_class_entry zend_class_entry
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define zend_string_equals_ci(s1, s2)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define zend_string_equals_literal_ci(str, c)
#define MAY_BE_STATIC
#define MAY_BE_NEVER
#define MAY_BE_ANY
#define MAY_BE_OBJECT
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZEND_TYPE_PURE_MASK(t)
Definition zend_types.h:257
#define Z_TRY_ADDREF_P(pz)
#define ZEND_TYPE_NAME(t)
Definition zend_types.h:198
#define ZVAL_UNDEF(z)
#define IS_FALSE
Definition zend_types.h:602
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_CONSTANT_FLAGS(zval)
Definition zend_types.h:692
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define HT_USED_SIZE(ht)
Definition zend_types.h:476
#define IS_STRING
Definition zend_types.h:606
#define _ZEND_TYPE_ARENA_BIT
Definition zend_types.h:156
#define ZEND_TYPE_IS_INTERSECTION(t)
Definition zend_types.h:186
#define Z_REFCOUNTED_P(zval_p)
Definition zend_types.h:921
#define ZVAL_COPY_VALUE_PROP(z, v)
#define ZSTR_SET_CE_CACHE(s, ce)
Definition zend_types.h:843
#define ZVAL_INDIRECT(z, v)
struct _zend_array HashTable
Definition zend_types.h:386
#define IS_ARRAY
Definition zend_types.h:607
#define IS_VOID
Definition zend_types.h:617
#define ZVAL_COPY_OR_DUP(z, v)
#define ZEND_TYPE_LIST_SIZE(num_types)
Definition zend_types.h:207
#define ZEND_TYPE_HAS_NAME(t)
Definition zend_types.h:174
#define HT_SIZE(ht)
Definition zend_types.h:474
#define Z_PTR_P(zval_p)
#define GC_FLAGS(p)
Definition zend_types.h:756
#define ZSTR_HAS_CE_CACHE(s)
Definition zend_types.h:841
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_FUNC_P(zval_p)
#define ZEND_TYPE_FULL_MASK(t)
Definition zend_types.h:254
#define ZEND_TYPE_FOREACH(type, type_ptr)
Definition zend_types.h:223
#define Z_PTR(zval)
#define ZEND_TYPE_HAS_LIST(t)
Definition zend_types.h:180
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define ZEND_TYPE_LIST_FOREACH_END()
Definition zend_types.h:217
#define IS_NULL
Definition zend_types.h:601
@ FAILURE
Definition zend_types.h:61
#define Z_TRY_ADDREF(z)
#define ZEND_TYPE_SET_LIST(t, list)
Definition zend_types.h:249
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
#define ZEND_TYPE_FOREACH_END()
Definition zend_types.h:236
uint32_t HashPosition
Definition zend_types.h:548
#define HT_GET_DATA_ADDR(ht)
Definition zend_types.h:545
struct _Bucket Bucket
#define Z_INDIRECT_P(zval_p)
#define HT_SET_DATA_ADDR(ht, ptr)
Definition zend_types.h:542
#define IS_PROP_UNINIT
#define IS_ARRAY_IMMUTABLE
Definition zend_types.h:823
#define IS_CONSTANT_AST
Definition zend_types.h:611
#define ZVAL_COPY_PROP(z, v)
#define Z_CE_P(zval_p)
#define ZEND_TYPE_LIST_FOREACH(list, type_ptr)
Definition zend_types.h:211
#define Z_PROP_FLAG_P(z)
#define Z_TYPE(zval)
Definition zend_types.h:659
#define ZEND_TYPE_CONTAINS_CODE(t, code)
Definition zend_types.h:266
#define IS_INDIRECT
Definition zend_types.h:623
#define ZEND_TYPE_LIST(t)
Definition zend_types.h:204
struct _zend_ast zend_ast
Definition zend_types.h:102
#define Z_ASTVAL_P(zval_p)
#define ZVAL_COPY_VALUE(z, v)
#define ZVAL_DEINDIRECT(z)
#define Z_OPT_TYPE_P(zval_p)
Definition zend_types.h:938
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
new_op_array
zend_property_info * prop_info
zend_string * name
bool result
op2
op1
zval * ret
new_op_array scope
#define ZEND_RECV_INIT
#define ZEND_RECV