1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2018 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@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
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_smart_str.h"
26 #include "zend_inheritance.h"
27
overriden_ptr_dtor(zval * zv)28 static void overriden_ptr_dtor(zval *zv) /* {{{ */
29 {
30 efree_size(Z_PTR_P(zv), sizeof(zend_function));
31 }
32 /* }}} */
33
zend_duplicate_property_info(zend_property_info * property_info)34 static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
35 {
36 zend_property_info* new_property_info;
37
38 new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
39 memcpy(new_property_info, property_info, sizeof(zend_property_info));
40 zend_string_addref(new_property_info->name);
41 if (new_property_info->doc_comment) {
42 zend_string_addref(new_property_info->doc_comment);
43 }
44 return new_property_info;
45 }
46 /* }}} */
47
zend_duplicate_property_info_internal(zend_property_info * property_info)48 static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
49 {
50 zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
51 memcpy(new_property_info, property_info, sizeof(zend_property_info));
52 zend_string_addref(new_property_info->name);
53 return new_property_info;
54 }
55 /* }}} */
56
zend_duplicate_function(zend_function * func,zend_class_entry * ce)57 static zend_function *zend_duplicate_function(zend_function *func, zend_class_entry *ce) /* {{{ */
58 {
59 zend_function *new_function;
60
61 if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
62 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
63 new_function = pemalloc(sizeof(zend_internal_function), 1);
64 memcpy(new_function, func, sizeof(zend_internal_function));
65 } else {
66 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
67 memcpy(new_function, func, sizeof(zend_internal_function));
68 new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
69 }
70 if (EXPECTED(new_function->common.function_name)) {
71 zend_string_addref(new_function->common.function_name);
72 }
73 } else {
74 if (func->op_array.refcount) {
75 (*func->op_array.refcount)++;
76 }
77 if (EXPECTED(!func->op_array.static_variables)) {
78 /* reuse the same op_array structure */
79 return func;
80 }
81 if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
82 GC_REFCOUNT(func->op_array.static_variables)++;
83 }
84 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
85 memcpy(new_function, func, sizeof(zend_op_array));
86 }
87 return new_function;
88 }
89 /* }}} */
90
do_inherit_parent_constructor(zend_class_entry * ce)91 static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
92 {
93 ZEND_ASSERT(ce->parent != NULL);
94
95 /* You cannot change create_object */
96 ce->create_object = ce->parent->create_object;
97
98 /* Inherit special functions if needed */
99 if (EXPECTED(!ce->get_iterator)) {
100 ce->get_iterator = ce->parent->get_iterator;
101 }
102 if (EXPECTED(!ce->iterator_funcs.funcs)) {
103 ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
104 }
105 if (EXPECTED(!ce->__get)) {
106 ce->__get = ce->parent->__get;
107 }
108 if (EXPECTED(!ce->__set)) {
109 ce->__set = ce->parent->__set;
110 }
111 if (EXPECTED(!ce->__unset)) {
112 ce->__unset = ce->parent->__unset;
113 }
114 if (EXPECTED(!ce->__isset)) {
115 ce->__isset = ce->parent->__isset;
116 }
117 if (EXPECTED(!ce->__call)) {
118 ce->__call = ce->parent->__call;
119 }
120 if (EXPECTED(!ce->__callstatic)) {
121 ce->__callstatic = ce->parent->__callstatic;
122 }
123 if (EXPECTED(!ce->__tostring)) {
124 ce->__tostring = ce->parent->__tostring;
125 }
126 if (EXPECTED(!ce->clone)) {
127 ce->clone = ce->parent->clone;
128 }
129 if (EXPECTED(!ce->serialize)) {
130 ce->serialize = ce->parent->serialize;
131 }
132 if (EXPECTED(!ce->unserialize)) {
133 ce->unserialize = ce->parent->unserialize;
134 }
135 if (!ce->destructor) {
136 ce->destructor = ce->parent->destructor;
137 }
138 if (EXPECTED(!ce->__debugInfo)) {
139 ce->__debugInfo = ce->parent->__debugInfo;
140 }
141
142 if (ce->constructor) {
143 if (ce->parent->constructor && UNEXPECTED(ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
144 zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
145 ZSTR_VAL(ce->parent->name), ZSTR_VAL(ce->parent->constructor->common.function_name),
146 ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
147 }
148 return;
149 }
150
151 ce->constructor = ce->parent->constructor;
152 }
153 /* }}} */
154
zend_visibility_string(uint32_t fn_flags)155 char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
156 {
157 if (fn_flags & ZEND_ACC_PRIVATE) {
158 return "private";
159 }
160 if (fn_flags & ZEND_ACC_PROTECTED) {
161 return "protected";
162 }
163 if (fn_flags & ZEND_ACC_PUBLIC) {
164 return "public";
165 }
166 return "";
167 }
168 /* }}} */
169
zend_iterable_compatibility_check(zend_arg_info * arg_info)170 static zend_always_inline zend_bool zend_iterable_compatibility_check(zend_arg_info *arg_info) /* {{{ */
171 {
172 if (arg_info->type_hint == IS_ARRAY) {
173 return 1;
174 }
175
176 if (arg_info->class_name && zend_string_equals_literal_ci(arg_info->class_name, "Traversable")) {
177 return 1;
178 }
179
180 return 0;
181 }
182 /* }}} */
183
zend_do_perform_type_hint_check(const zend_function * fe,zend_arg_info * fe_arg_info,const zend_function * proto,zend_arg_info * proto_arg_info)184 static int zend_do_perform_type_hint_check(const zend_function *fe, zend_arg_info *fe_arg_info, const zend_function *proto, zend_arg_info *proto_arg_info) /* {{{ */
185 {
186 if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
187 /* Only one has a type declaration and the other one doesn't */
188 return 0;
189 }
190
191 if (fe_arg_info->class_name) {
192 zend_string *fe_class_name, *proto_class_name;
193 const char *class_name;
194
195 if (fe->type == ZEND_INTERNAL_FUNCTION) {
196 fe_class_name = NULL;
197 class_name = ((zend_internal_arg_info*)fe_arg_info)->class_name;
198 } else {
199 fe_class_name = fe_arg_info->class_name;
200 class_name = ZSTR_VAL(fe_arg_info->class_name);
201 }
202 if (!strcasecmp(class_name, "parent") && proto->common.scope) {
203 fe_class_name = zend_string_copy(proto->common.scope->name);
204 } else if (!strcasecmp(class_name, "self") && fe->common.scope) {
205 fe_class_name = zend_string_copy(fe->common.scope->name);
206 } else if (fe_class_name) {
207 zend_string_addref(fe_class_name);
208 } else {
209 fe_class_name = zend_string_init(class_name, strlen(class_name), 0);
210 }
211
212 if (proto->type == ZEND_INTERNAL_FUNCTION) {
213 proto_class_name = NULL;
214 class_name = ((zend_internal_arg_info*)proto_arg_info)->class_name;
215 } else {
216 proto_class_name = proto_arg_info->class_name;
217 class_name = ZSTR_VAL(proto_arg_info->class_name);
218 }
219 if (!strcasecmp(class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
220 proto_class_name = zend_string_copy(proto->common.scope->parent->name);
221 } else if (!strcasecmp(class_name, "self") && proto->common.scope) {
222 proto_class_name = zend_string_copy(proto->common.scope->name);
223 } else if (proto_class_name) {
224 zend_string_addref(proto_class_name);
225 } else {
226 proto_class_name = zend_string_init(class_name, strlen(class_name), 0);
227 }
228
229 if (strcasecmp(ZSTR_VAL(fe_class_name), ZSTR_VAL(proto_class_name)) != 0) {
230 if (fe->common.type != ZEND_USER_FUNCTION) {
231 zend_string_release(proto_class_name);
232 zend_string_release(fe_class_name);
233 return 0;
234 } else {
235 zend_class_entry *fe_ce, *proto_ce;
236
237 fe_ce = zend_lookup_class(fe_class_name);
238 proto_ce = zend_lookup_class(proto_class_name);
239
240 /* Check for class alias */
241 if (!fe_ce || !proto_ce ||
242 fe_ce->type == ZEND_INTERNAL_CLASS ||
243 proto_ce->type == ZEND_INTERNAL_CLASS ||
244 fe_ce != proto_ce) {
245 zend_string_release(proto_class_name);
246 zend_string_release(fe_class_name);
247 return 0;
248 }
249 }
250 }
251 zend_string_release(proto_class_name);
252 zend_string_release(fe_class_name);
253 }
254
255 if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
256 /* Incompatible type */
257 return 0;
258 }
259
260 return 1;
261 }
262 /* }}} */
263
zend_do_perform_implementation_check(const zend_function * fe,const zend_function * proto)264 static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto) /* {{{ */
265 {
266 uint32_t i, num_args;
267
268 /* If it's a user function then arg_info == NULL means we don't have any parameters but
269 * we still need to do the arg number checks. We are only willing to ignore this for internal
270 * functions because extensions don't always define arg_info.
271 */
272 if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
273 return 1;
274 }
275
276 /* Checks for constructors only if they are declared in an interface,
277 * or explicitly marked as abstract
278 */
279 if ((fe->common.fn_flags & ZEND_ACC_CTOR)
280 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
281 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
282 return 1;
283 }
284
285 /* If the prototype method is private do not enforce a signature */
286 if (proto->common.fn_flags & ZEND_ACC_PRIVATE) {
287 return 1;
288 }
289
290 /* check number of arguments */
291 if (proto->common.required_num_args < fe->common.required_num_args
292 || proto->common.num_args > fe->common.num_args) {
293 return 0;
294 }
295
296 /* by-ref constraints on return values are covariant */
297 if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
298 && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
299 return 0;
300 }
301
302 if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
303 && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
304 return 0;
305 }
306
307 /* For variadic functions any additional (optional) arguments that were added must be
308 * checked against the signature of the variadic argument, so in this case we have to
309 * go through all the parameters of the function and not just those present in the
310 * prototype. */
311 num_args = proto->common.num_args;
312 if (proto->common.fn_flags & ZEND_ACC_VARIADIC) {
313 num_args++;
314 if (fe->common.num_args >= proto->common.num_args) {
315 num_args = fe->common.num_args;
316 if (fe->common.fn_flags & ZEND_ACC_VARIADIC) {
317 num_args++;
318 }
319 }
320 }
321
322 for (i = 0; i < num_args; i++) {
323 zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
324
325 zend_arg_info *proto_arg_info;
326 if (i < proto->common.num_args) {
327 proto_arg_info = &proto->common.arg_info[i];
328 } else {
329 proto_arg_info = &proto->common.arg_info[proto->common.num_args];
330 }
331
332 if (!zend_do_perform_type_hint_check(fe, fe_arg_info, proto, proto_arg_info)) {
333 switch (fe_arg_info->type_hint) {
334 case IS_ITERABLE:
335 if (!zend_iterable_compatibility_check(proto_arg_info)) {
336 return 0;
337 }
338 break;
339
340 default:
341 return 0;
342 }
343 }
344
345 // This introduces BC break described at https://bugs.php.net/bug.php?id=72119
346 if (proto_arg_info->type_hint && proto_arg_info->allow_null && !fe_arg_info->allow_null) {
347 /* incompatible nullability */
348 return 0;
349 }
350
351 /* by-ref constraints on arguments are invariant */
352 if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
353 return 0;
354 }
355 }
356
357 /* Check return type compatibility, but only if the prototype already specifies
358 * a return type. Adding a new return type is always valid. */
359 if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
360 /* Removing a return type is not valid. */
361 if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
362 return 0;
363 }
364
365 if (!zend_do_perform_type_hint_check(fe, fe->common.arg_info - 1, proto, proto->common.arg_info - 1)) {
366 switch (proto->common.arg_info[-1].type_hint) {
367 case IS_ITERABLE:
368 if (!zend_iterable_compatibility_check(fe->common.arg_info - 1)) {
369 return 0;
370 }
371 break;
372
373 default:
374 return 0;
375 }
376 }
377
378 if (fe->common.arg_info[-1].allow_null && !proto->common.arg_info[-1].allow_null) {
379 return 0;
380 }
381 }
382 return 1;
383 }
384 /* }}} */
385
zend_append_type_hint(smart_str * str,const zend_function * fptr,zend_arg_info * arg_info,int return_hint)386 static ZEND_COLD void zend_append_type_hint(smart_str *str, const zend_function *fptr, zend_arg_info *arg_info, int return_hint) /* {{{ */
387 {
388
389 if (arg_info->type_hint != IS_UNDEF && arg_info->allow_null) {
390 smart_str_appendc(str, '?');
391 }
392
393 if (arg_info->class_name) {
394 const char *class_name;
395 size_t class_name_len;
396
397 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
398 class_name = ((zend_internal_arg_info*)arg_info)->class_name;
399 class_name_len = strlen(class_name);
400 } else {
401 class_name = ZSTR_VAL(arg_info->class_name);
402 class_name_len = ZSTR_LEN(arg_info->class_name);
403 }
404
405 if (!strcasecmp(class_name, "self") && fptr->common.scope) {
406 class_name = ZSTR_VAL(fptr->common.scope->name);
407 class_name_len = ZSTR_LEN(fptr->common.scope->name);
408 } else if (!strcasecmp(class_name, "parent") && fptr->common.scope && fptr->common.scope->parent) {
409 class_name = ZSTR_VAL(fptr->common.scope->parent->name);
410 class_name_len = ZSTR_LEN(fptr->common.scope->parent->name);
411 }
412
413 smart_str_appendl(str, class_name, class_name_len);
414 if (!return_hint) {
415 smart_str_appendc(str, ' ');
416 }
417 } else if (arg_info->type_hint) {
418 if (arg_info->type_hint == IS_LONG) {
419 smart_str_appendl(str, "int", 3);
420 } else if (arg_info->type_hint == _IS_BOOL) {
421 smart_str_appendl(str, "bool", 4);
422 } else {
423 const char *type_name = zend_get_type_by_const(arg_info->type_hint);
424 smart_str_appends(str, type_name);
425 }
426 if (!return_hint) {
427 smart_str_appendc(str, ' ');
428 }
429 }
430 }
431 /* }}} */
432
zend_get_function_declaration(const zend_function * fptr)433 static ZEND_COLD zend_string *zend_get_function_declaration(const zend_function *fptr) /* {{{ */
434 {
435 smart_str str = {0};
436
437 if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
438 smart_str_appends(&str, "& ");
439 }
440
441 if (fptr->common.scope) {
442 /* cut off on NULL byte ... class@anonymous */
443 smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), strlen(ZSTR_VAL(fptr->common.scope->name)));
444 smart_str_appends(&str, "::");
445 }
446
447 smart_str_append(&str, fptr->common.function_name);
448 smart_str_appendc(&str, '(');
449
450 if (fptr->common.arg_info) {
451 uint32_t i, num_args, required;
452 zend_arg_info *arg_info = fptr->common.arg_info;
453
454 required = fptr->common.required_num_args;
455 num_args = fptr->common.num_args;
456 if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
457 num_args++;
458 }
459 for (i = 0; i < num_args;) {
460 zend_append_type_hint(&str, fptr, arg_info, 0);
461
462 if (arg_info->pass_by_reference) {
463 smart_str_appendc(&str, '&');
464 }
465
466 if (arg_info->is_variadic) {
467 smart_str_appends(&str, "...");
468 }
469
470 smart_str_appendc(&str, '$');
471
472 if (arg_info->name) {
473 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
474 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
475 } else {
476 smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
477 }
478 } else {
479 smart_str_appends(&str, "param");
480 smart_str_append_unsigned(&str, i);
481 }
482
483 if (i >= required && !arg_info->is_variadic) {
484 smart_str_appends(&str, " = ");
485 if (fptr->type == ZEND_USER_FUNCTION) {
486 zend_op *precv = NULL;
487 {
488 uint32_t idx = i;
489 zend_op *op = fptr->op_array.opcodes;
490 zend_op *end = op + fptr->op_array.last;
491
492 ++idx;
493 while (op < end) {
494 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
495 && op->op1.num == (zend_ulong)idx)
496 {
497 precv = op;
498 }
499 ++op;
500 }
501 }
502 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
503 zval *zv = RT_CONSTANT(&fptr->op_array, precv->op2);
504
505 if (Z_TYPE_P(zv) == IS_CONSTANT) {
506 smart_str_append(&str, Z_STR_P(zv));
507 } else if (Z_TYPE_P(zv) == IS_FALSE) {
508 smart_str_appends(&str, "false");
509 } else if (Z_TYPE_P(zv) == IS_TRUE) {
510 smart_str_appends(&str, "true");
511 } else if (Z_TYPE_P(zv) == IS_NULL) {
512 smart_str_appends(&str, "NULL");
513 } else if (Z_TYPE_P(zv) == IS_STRING) {
514 smart_str_appendc(&str, '\'');
515 smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
516 if (Z_STRLEN_P(zv) > 10) {
517 smart_str_appends(&str, "...");
518 }
519 smart_str_appendc(&str, '\'');
520 } else if (Z_TYPE_P(zv) == IS_ARRAY) {
521 smart_str_appends(&str, "Array");
522 } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
523 smart_str_appends(&str, "<expression>");
524 } else {
525 zend_string *zv_str = zval_get_string(zv);
526 smart_str_append(&str, zv_str);
527 zend_string_release(zv_str);
528 }
529 }
530 } else {
531 smart_str_appends(&str, "NULL");
532 }
533 }
534
535 if (++i < num_args) {
536 smart_str_appends(&str, ", ");
537 }
538 arg_info++;
539 }
540 }
541
542 smart_str_appendc(&str, ')');
543
544 if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
545 smart_str_appends(&str, ": ");
546 zend_append_type_hint(&str, fptr, fptr->common.arg_info - 1, 1);
547 }
548 smart_str_0(&str);
549
550 return str.s;
551 }
552 /* }}} */
553
do_inheritance_check_on_method(zend_function * child,zend_function * parent)554 static void do_inheritance_check_on_method(zend_function *child, zend_function *parent) /* {{{ */
555 {
556 uint32_t child_flags;
557 uint32_t parent_flags = parent->common.fn_flags;
558
559 if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
560 && parent->common.fn_flags & ZEND_ACC_ABSTRACT
561 && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
562 && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
563 zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
564 ZSTR_VAL(parent->common.scope->name),
565 ZSTR_VAL(child->common.function_name),
566 child->common.prototype ? ZSTR_VAL(child->common.prototype->common.scope->name) : ZSTR_VAL(child->common.scope->name));
567 }
568
569 if (UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
570 zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
571 }
572
573 child_flags = child->common.fn_flags;
574 /* You cannot change from static to non static and vice versa.
575 */
576 if (UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
577 if (child->common.fn_flags & ZEND_ACC_STATIC) {
578 zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
579 } else {
580 zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
581 }
582 }
583
584 /* Disallow making an inherited method abstract. */
585 if (UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
586 zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
587 }
588
589 /* Prevent derived classes from restricting access that was available in parent classes */
590 if (UNEXPECTED((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK))) {
591 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", 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");
592 }
593
594 if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
595 && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
596 child->common.fn_flags |= ZEND_ACC_CHANGED;
597 }
598 if (parent_flags & ZEND_ACC_CHANGED) {
599 child->common.fn_flags |= ZEND_ACC_CHANGED;
600 }
601
602 if (parent_flags & ZEND_ACC_PRIVATE) {
603 child->common.prototype = NULL;
604 } else if (parent_flags & ZEND_ACC_ABSTRACT) {
605 child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
606 child->common.prototype = parent;
607 } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
608 /* ctors only have a prototype if it comes from an interface */
609 child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
610 }
611
612 if (child->common.prototype && (
613 child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT
614 )) {
615 parent = child->common.prototype;
616 }
617 if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) {
618 int error_level;
619 const char *error_verb;
620 zend_string *method_prototype = zend_get_function_declaration(parent);
621 zend_string *child_prototype = zend_get_function_declaration(child);
622
623 if (child->common.prototype && (
624 child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT
625 )) {
626 error_level = E_COMPILE_ERROR;
627 error_verb = "must";
628 } else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
629 (!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
630 !zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) ||
631 (child->common.arg_info[-1].allow_null && !parent->common.arg_info[-1].allow_null))) {
632 error_level = E_COMPILE_ERROR;
633 error_verb = "must";
634 } else {
635 error_level = E_WARNING;
636 error_verb = "should";
637 }
638 zend_error(error_level, "Declaration of %s %s be compatible with %s", ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype));
639 zend_string_free(child_prototype);
640 zend_string_free(method_prototype);
641 }
642 }
643 /* }}} */
644
do_inherit_method(zend_string * key,zend_function * parent,zend_class_entry * ce)645 static zend_function *do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce) /* {{{ */
646 {
647 zval *child = zend_hash_find(&ce->function_table, key);
648
649 if (child) {
650 zend_function *func = (zend_function*)Z_PTR_P(child);
651 zend_function *orig_prototype = func->common.prototype;
652
653 do_inheritance_check_on_method(func, parent);
654 if (func->common.prototype != orig_prototype &&
655 func->type == ZEND_USER_FUNCTION &&
656 func->common.scope != ce &&
657 !func->op_array.static_variables) {
658 /* Lazy duplication */
659 zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
660 memcpy(new_function, func, sizeof(zend_op_array));
661 Z_PTR_P(child) = new_function;
662 func->common.prototype = orig_prototype;
663 }
664 return NULL;
665 }
666
667 if (parent->common.fn_flags & (ZEND_ACC_ABSTRACT)) {
668 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
669 }
670
671 return zend_duplicate_function(parent, ce);
672 }
673 /* }}} */
674
do_inherit_property(zend_property_info * parent_info,zend_string * key,zend_class_entry * ce)675 static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
676 {
677 zval *child = zend_hash_find(&ce->properties_info, key);
678 zend_property_info *child_info;
679
680 if (UNEXPECTED(child)) {
681 child_info = Z_PTR_P(child);
682 if (UNEXPECTED(parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW))) {
683 child_info->flags |= ZEND_ACC_CHANGED;
684 } else {
685 if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
686 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
687 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->parent->name), ZSTR_VAL(key),
688 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
689 }
690
691 if (parent_info->flags & ZEND_ACC_CHANGED) {
692 child_info->flags |= ZEND_ACC_CHANGED;
693 }
694
695 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
696 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(ce->parent->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
697 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
698 int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
699 int child_num = OBJ_PROP_TO_NUM(child_info->offset);
700
701 /* Don't keep default properties in GC (they may be freed by opcache) */
702 zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
703 ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
704 ZVAL_UNDEF(&ce->default_properties_table[child_num]);
705 child_info->offset = parent_info->offset;
706 }
707 }
708 } else {
709 if (UNEXPECTED(parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW))) {
710 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
711 child_info = zend_duplicate_property_info_internal(parent_info);
712 } else {
713 child_info = zend_duplicate_property_info(parent_info);
714 }
715 child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
716 child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
717 } else {
718 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
719 child_info = zend_duplicate_property_info_internal(parent_info);
720 } else {
721 child_info = parent_info;
722 }
723 }
724 _zend_hash_append_ptr(&ce->properties_info, key, child_info);
725 }
726 }
727 /* }}} */
728
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)729 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
730 {
731 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
732 zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
733 }
734 if (UNEXPECTED(ce == iface)) {
735 zend_error_noreturn(E_ERROR, "Interface %s cannot implement itself", ZSTR_VAL(ce->name));
736 }
737 }
738 /* }}} */
739
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface)740 ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
741 {
742 /* expects interface to be contained in ce's interface list already */
743 uint32_t i, ce_num, if_num = iface->num_interfaces;
744 zend_class_entry *entry;
745
746 if (if_num==0) {
747 return;
748 }
749 ce_num = ce->num_interfaces;
750
751 if (ce->type == ZEND_INTERNAL_CLASS) {
752 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
753 } else {
754 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
755 }
756
757 /* Inherit the interfaces, only if they're not already inherited by the class */
758 while (if_num--) {
759 entry = iface->interfaces[if_num];
760 for (i = 0; i < ce_num; i++) {
761 if (ce->interfaces[i] == entry) {
762 break;
763 }
764 }
765 if (i == ce_num) {
766 ce->interfaces[ce->num_interfaces++] = entry;
767 }
768 }
769
770 /* and now call the implementing handlers */
771 while (ce_num < ce->num_interfaces) {
772 do_implement_interface(ce, ce->interfaces[ce_num++]);
773 }
774 }
775 /* }}} */
776
do_inherit_class_constant(zend_string * name,zend_class_constant * parent_const,zend_class_entry * ce)777 static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
778 {
779 zend_class_constant *c = zend_hash_find_ptr(&ce->constants_table, name);
780
781 if (c != NULL) {
782 if (UNEXPECTED((Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PPP_MASK) > (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PPP_MASK))) {
783 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
784 ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(Z_ACCESS_FLAGS(parent_const->value)), ZSTR_VAL(ce->parent->name), (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PUBLIC) ? "" : " or weaker");
785 }
786 } else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) {
787 if (Z_CONSTANT(parent_const->value)) {
788 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
789 }
790 if (ce->type & ZEND_INTERNAL_CLASS) {
791 if (Z_REFCOUNTED(parent_const->value)) {
792 Z_ADDREF(parent_const->value);
793 }
794 c = pemalloc(sizeof(zend_class_constant), 1);
795 memcpy(c, parent_const, sizeof(zend_class_constant));
796 } else {
797 c = parent_const;
798 }
799 _zend_hash_append_ptr(&ce->constants_table, name, c);
800 }
801 }
802 /* }}} */
803
zend_do_inheritance(zend_class_entry * ce,zend_class_entry * parent_ce)804 ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
805 {
806 zend_property_info *property_info;
807 zend_function *func;
808 zend_string *key;
809
810 if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
811 /* Interface can only inherit other interfaces */
812 if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
813 zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
814 }
815 } else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL))) {
816 /* Class declaration must not extend traits or interfaces */
817 if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
818 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
819 } else if (parent_ce->ce_flags & ZEND_ACC_TRAIT) {
820 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
821 }
822
823 /* Class must not extend a final class */
824 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
825 zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
826 }
827 }
828
829 ce->parent = parent_ce;
830
831 /* Inherit interfaces */
832 zend_do_inherit_interfaces(ce, parent_ce);
833
834 /* Inherit properties */
835 if (parent_ce->default_properties_count) {
836 zval *src, *dst, *end;
837
838 if (ce->default_properties_count) {
839 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
840 src = ce->default_properties_table + ce->default_properties_count;
841 end = table + parent_ce->default_properties_count;
842 dst = end + ce->default_properties_count;
843 ce->default_properties_table = table;
844 do {
845 dst--;
846 src--;
847 ZVAL_COPY_VALUE(dst, src);
848 } while (dst != end);
849 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
850 end = ce->default_properties_table;
851 } else {
852 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
853 dst = end + parent_ce->default_properties_count;
854 ce->default_properties_table = end;
855 }
856 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
857 do {
858 dst--;
859 src--;
860 #ifdef ZTS
861 if (parent_ce->type != ce->type) {
862 ZVAL_DUP(dst, src);
863 if (Z_OPT_CONSTANT_P(dst)) {
864 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
865 }
866 continue;
867 }
868 #endif
869
870 ZVAL_COPY(dst, src);
871 if (Z_OPT_CONSTANT_P(dst)) {
872 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
873 }
874 } while (dst != end);
875 ce->default_properties_count += parent_ce->default_properties_count;
876 }
877
878 if (parent_ce->default_static_members_count) {
879 zval *src, *dst, *end;
880
881 if (ce->default_static_members_count) {
882 zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
883 src = ce->default_static_members_table + ce->default_static_members_count;
884 end = table + parent_ce->default_static_members_count;
885 dst = end + ce->default_static_members_count;
886 ce->default_static_members_table = table;
887 do {
888 dst--;
889 src--;
890 ZVAL_COPY_VALUE(dst, src);
891 } while (dst != end);
892 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
893 end = ce->default_static_members_table;
894 } else {
895 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
896 dst = end + parent_ce->default_static_members_count;
897 ce->default_static_members_table = end;
898 }
899 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
900 do {
901 dst--;
902 src--;
903 if (parent_ce->type == ZEND_INTERNAL_CLASS) {
904 if (!Z_ISREF_P(src)) {
905 ZVAL_NEW_PERSISTENT_REF(src, src);
906 }
907 } else {
908 ZVAL_MAKE_REF(src);
909 }
910 ZVAL_COPY_VALUE(dst, src);
911 Z_ADDREF_P(dst);
912 if (Z_CONSTANT_P(Z_REFVAL_P(dst))) {
913 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
914 }
915 } while (dst != end);
916 ce->default_static_members_count += parent_ce->default_static_members_count;
917 if (ce->type == ZEND_USER_CLASS) {
918 ce->static_members_table = ce->default_static_members_table;
919 } else {
920 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
921 }
922 }
923
924 ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
925 if (property_info->ce == ce) {
926 if (property_info->flags & ZEND_ACC_STATIC) {
927 property_info->offset += parent_ce->default_static_members_count;
928 } else {
929 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
930 }
931 }
932 } ZEND_HASH_FOREACH_END();
933
934 if (zend_hash_num_elements(&parent_ce->properties_info)) {
935 zend_hash_extend(&ce->properties_info,
936 zend_hash_num_elements(&ce->properties_info) +
937 zend_hash_num_elements(&parent_ce->properties_info), 0);
938
939 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
940 do_inherit_property(property_info, key, ce);
941 } ZEND_HASH_FOREACH_END();
942 }
943
944 if (zend_hash_num_elements(&parent_ce->constants_table)) {
945 zend_class_constant *c;
946
947 zend_hash_extend(&ce->constants_table,
948 zend_hash_num_elements(&ce->constants_table) +
949 zend_hash_num_elements(&parent_ce->constants_table), 0);
950
951 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
952 do_inherit_class_constant(key, c, ce);
953 } ZEND_HASH_FOREACH_END();
954 }
955
956 if (zend_hash_num_elements(&parent_ce->function_table)) {
957 zend_hash_extend(&ce->function_table,
958 zend_hash_num_elements(&ce->function_table) +
959 zend_hash_num_elements(&parent_ce->function_table), 0);
960
961 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
962 zend_function *new_func = do_inherit_method(key, func, ce);
963
964 if (new_func) {
965 _zend_hash_append_ptr(&ce->function_table, key, new_func);
966 }
967 } ZEND_HASH_FOREACH_END();
968 }
969
970 do_inherit_parent_constructor(ce);
971
972 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
973 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
974 } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
975 /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
976 zend_verify_abstract_class(ce);
977 }
978 ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_USE_GUARDS);
979 }
980 /* }}} */
981
do_inherit_constant_check(HashTable * child_constants_table,zend_class_constant * parent_constant,zend_string * name,const zend_class_entry * iface)982 static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zend_class_constant *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
983 {
984 zend_class_constant *old_constant;
985
986 if ((old_constant = zend_hash_find_ptr(child_constants_table, name)) != NULL) {
987 if (old_constant->ce != parent_constant->ce) {
988 zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", ZSTR_VAL(name), ZSTR_VAL(iface->name));
989 }
990 return 0;
991 }
992 return 1;
993 }
994 /* }}} */
995
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)996 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
997 {
998 if (do_inherit_constant_check(&ce->constants_table, c, name, iface)) {
999 zend_class_constant *ct;
1000 if (Z_CONSTANT(c->value)) {
1001 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1002 }
1003 if (ce->type & ZEND_INTERNAL_CLASS) {
1004 if (Z_REFCOUNTED(c->value)) {
1005 Z_ADDREF(c->value);
1006 }
1007 ct = pemalloc(sizeof(zend_class_constant), 1);
1008 memcpy(ct, c, sizeof(zend_class_constant));
1009 } else {
1010 ct = c;
1011 }
1012 zend_hash_update_ptr(&ce->constants_table, name, ct);
1013 }
1014 }
1015 /* }}} */
1016
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1017 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1018 {
1019 uint32_t i, ignore = 0;
1020 uint32_t current_iface_num = ce->num_interfaces;
1021 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
1022 zend_function *func;
1023 zend_string *key;
1024 zend_class_constant *c;
1025
1026 for (i = 0; i < ce->num_interfaces; i++) {
1027 if (ce->interfaces[i] == NULL) {
1028 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1029 i--;
1030 } else if (ce->interfaces[i] == iface) {
1031 if (EXPECTED(i < parent_iface_num)) {
1032 ignore = 1;
1033 } else {
1034 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1035 }
1036 }
1037 }
1038 if (ignore) {
1039 /* Check for attempt to redeclare interface constants */
1040 ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
1041 do_inherit_constant_check(&iface->constants_table, c, key, iface);
1042 } ZEND_HASH_FOREACH_END();
1043 } else {
1044 if (ce->num_interfaces >= current_iface_num) {
1045 if (ce->type == ZEND_INTERNAL_CLASS) {
1046 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1047 } else {
1048 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1049 }
1050 }
1051 ce->interfaces[ce->num_interfaces++] = iface;
1052
1053 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1054 do_inherit_iface_constant(key, c, ce, iface);
1055 } ZEND_HASH_FOREACH_END();
1056
1057 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1058 zend_function *new_func = do_inherit_method(key, func, ce);
1059
1060 if (new_func) {
1061 zend_hash_add_new_ptr(&ce->function_table, key, new_func);
1062 }
1063 } ZEND_HASH_FOREACH_END();
1064
1065 do_implement_interface(ce, iface);
1066 zend_do_inherit_interfaces(ce, iface);
1067 }
1068 }
1069 /* }}} */
1070
zend_do_implement_trait(zend_class_entry * ce,zend_class_entry * trait)1071 ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
1072 {
1073 uint32_t i, ignore = 0;
1074 uint32_t current_trait_num = ce->num_traits;
1075 uint32_t parent_trait_num = ce->parent ? ce->parent->num_traits : 0;
1076
1077 for (i = 0; i < ce->num_traits; i++) {
1078 if (ce->traits[i] == NULL) {
1079 memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
1080 i--;
1081 } else if (ce->traits[i] == trait) {
1082 if (i < parent_trait_num) {
1083 ignore = 1;
1084 }
1085 }
1086 }
1087 if (!ignore) {
1088 if (ce->num_traits >= current_trait_num) {
1089 if (ce->type == ZEND_INTERNAL_CLASS) {
1090 ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1091 } else {
1092 ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
1093 }
1094 }
1095 ce->traits[ce->num_traits++] = trait;
1096 }
1097 }
1098 /* }}} */
1099
zend_traits_method_compatibility_check(zend_function * fn,zend_function * other_fn)1100 static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn) /* {{{ */
1101 {
1102 uint32_t fn_flags = fn->common.scope->ce_flags;
1103 uint32_t other_flags = other_fn->common.scope->ce_flags;
1104
1105 return zend_do_perform_implementation_check(fn, other_fn)
1106 && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn))
1107 && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
1108 (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
1109 }
1110 /* }}} */
1111
zend_add_magic_methods(zend_class_entry * ce,zend_string * mname,zend_function * fe)1112 static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe) /* {{{ */
1113 {
1114 if (zend_string_equals_literal(mname, ZEND_CLONE_FUNC_NAME)) {
1115 ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
1116 } else if (zend_string_equals_literal(mname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
1117 if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
1118 zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
1119 }
1120 ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
1121 } else if (zend_string_equals_literal(mname, ZEND_DESTRUCTOR_FUNC_NAME)) {
1122 ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
1123 } else if (zend_string_equals_literal(mname, ZEND_GET_FUNC_NAME)) {
1124 ce->__get = fe;
1125 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1126 } else if (zend_string_equals_literal(mname, ZEND_SET_FUNC_NAME)) {
1127 ce->__set = fe;
1128 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1129 } else if (zend_string_equals_literal(mname, ZEND_CALL_FUNC_NAME)) {
1130 ce->__call = fe;
1131 } else if (zend_string_equals_literal(mname, ZEND_UNSET_FUNC_NAME)) {
1132 ce->__unset = fe;
1133 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1134 } else if (zend_string_equals_literal(mname, ZEND_ISSET_FUNC_NAME)) {
1135 ce->__isset = fe;
1136 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
1137 } else if (zend_string_equals_literal(mname, ZEND_CALLSTATIC_FUNC_NAME)) {
1138 ce->__callstatic = fe;
1139 } else if (zend_string_equals_literal(mname, ZEND_TOSTRING_FUNC_NAME)) {
1140 ce->__tostring = fe;
1141 } else if (zend_string_equals_literal(mname, ZEND_DEBUGINFO_FUNC_NAME)) {
1142 ce->__debugInfo = fe;
1143 } else if (ZSTR_LEN(ce->name) == ZSTR_LEN(mname)) {
1144 zend_string *lowercase_name = zend_string_tolower(ce->name);
1145 lowercase_name = zend_new_interned_string(lowercase_name);
1146 if (!memcmp(ZSTR_VAL(mname), ZSTR_VAL(lowercase_name), ZSTR_LEN(mname))) {
1147 if (ce->constructor && (!ce->parent || ce->constructor != ce->parent->constructor)) {
1148 zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ZSTR_VAL(ce->name));
1149 }
1150 ce->constructor = fe;
1151 fe->common.fn_flags |= ZEND_ACC_CTOR;
1152 }
1153 zend_string_release(lowercase_name);
1154 }
1155 }
1156 /* }}} */
1157
zend_add_trait_method(zend_class_entry * ce,const char * name,zend_string * key,zend_function * fn,HashTable ** overriden)1158 static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden) /* {{{ */
1159 {
1160 zend_function *existing_fn = NULL;
1161 zend_function *new_fn;
1162
1163 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1164 if (existing_fn->common.scope == ce) {
1165 /* members from the current class override trait methods */
1166 /* use temporary *overriden HashTable to detect hidden conflict */
1167 if (*overriden) {
1168 if ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
1169 if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1170 /* Make sure the trait method is compatible with previosly declared abstract method */
1171 if (UNEXPECTED(!zend_traits_method_compatibility_check(fn, existing_fn))) {
1172 zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1173 ZSTR_VAL(zend_get_function_declaration(fn)),
1174 ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1175 }
1176 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1177 /* Make sure the abstract declaration is compatible with previous declaration */
1178 if (UNEXPECTED(!zend_traits_method_compatibility_check(existing_fn, fn))) {
1179 zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1180 ZSTR_VAL(zend_get_function_declaration(fn)),
1181 ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1182 }
1183 return;
1184 }
1185 }
1186 } else {
1187 ALLOC_HASHTABLE(*overriden);
1188 zend_hash_init_ex(*overriden, 8, NULL, overriden_ptr_dtor, 0, 0);
1189 }
1190 zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
1191 return;
1192 } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT &&
1193 (existing_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0) {
1194 /* Make sure the trait method is compatible with previosly declared abstract method */
1195 if (UNEXPECTED(!zend_traits_method_compatibility_check(fn, existing_fn))) {
1196 zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1197 ZSTR_VAL(zend_get_function_declaration(fn)),
1198 ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1199 }
1200 } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1201 /* Make sure the abstract declaration is compatible with previous declaration */
1202 if (UNEXPECTED(!zend_traits_method_compatibility_check(existing_fn, fn))) {
1203 zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
1204 ZSTR_VAL(zend_get_function_declaration(fn)),
1205 ZSTR_VAL(zend_get_function_declaration(existing_fn)));
1206 }
1207 return;
1208 } else if (UNEXPECTED(existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)) {
1209 /* two traits can't define the same non-abstract method */
1210 #if 1
1211 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
1212 name, ZSTR_VAL(ce->name));
1213 #else /* TODO: better error message */
1214 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1215 ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
1216 ZSTR_VAL(ce->name), name,
1217 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
1218 #endif
1219 } else {
1220 /* inherited members are overridden by members inserted by traits */
1221 /* check whether the trait method fulfills the inheritance requirements */
1222 do_inheritance_check_on_method(fn, existing_fn);
1223 fn->common.prototype = NULL;
1224 }
1225 }
1226
1227 function_add_ref(fn);
1228 if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
1229 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
1230 memcpy(new_fn, fn, sizeof(zend_internal_function));
1231 new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
1232 } else {
1233 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1234 memcpy(new_fn, fn, sizeof(zend_op_array));
1235 }
1236 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1237 zend_add_magic_methods(ce, key, fn);
1238 }
1239 /* }}} */
1240
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)1241 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1242 {
1243 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1244
1245 fn->common.scope = ce;
1246
1247 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1248 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1249 }
1250 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
1251 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1252 }
1253 }
1254 }
1255 /* }}} */
1256
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable ** overriden,HashTable * exclude_table)1257 static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table) /* {{{ */
1258 {
1259 zend_trait_alias *alias, **alias_ptr;
1260 zend_string *lcname;
1261 zend_function fn_copy;
1262
1263 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
1264 if (ce->trait_aliases) {
1265 alias_ptr = ce->trait_aliases;
1266 alias = *alias_ptr;
1267 while (alias) {
1268 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1269 if (alias->alias != NULL
1270 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
1271 && ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname)
1272 && (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1273 fn_copy = *fn;
1274
1275 /* if it is 0, no modifieres has been changed */
1276 if (alias->modifiers) {
1277 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1278 }
1279
1280 lcname = zend_string_tolower(alias->alias);
1281 zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1282 zend_string_release(lcname);
1283
1284 /* Record the trait from which this alias was resolved. */
1285 if (!alias->trait_method->ce) {
1286 alias->trait_method->ce = fn->common.scope;
1287 }
1288 }
1289 alias_ptr++;
1290 alias = *alias_ptr;
1291 }
1292 }
1293
1294 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
1295 /* is not in hashtable, thus, function is not to be excluded */
1296 /* And how about ZEND_OVERLOADED_FUNCTION? */
1297 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION? sizeof(zend_op_array) : sizeof(zend_internal_function));
1298
1299 /* apply aliases which have not alias name, just setting visibility */
1300 if (ce->trait_aliases) {
1301 alias_ptr = ce->trait_aliases;
1302 alias = *alias_ptr;
1303 while (alias) {
1304 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1305 if (alias->alias == NULL && alias->modifiers != 0
1306 && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
1307 && (ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname))
1308 && (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1309
1310 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1311
1312 /** Record the trait from which this alias was resolved. */
1313 if (!alias->trait_method->ce) {
1314 alias->trait_method->ce = fn->common.scope;
1315 }
1316 }
1317 alias_ptr++;
1318 alias = *alias_ptr;
1319 }
1320 }
1321
1322 zend_add_trait_method(ce, ZSTR_VAL(fn->common.function_name), fnname, &fn_copy, overriden);
1323 }
1324
1325 return ZEND_HASH_APPLY_KEEP;
1326 }
1327 /* }}} */
1328
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait)1329 static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
1330 {
1331 uint32_t i;
1332
1333 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
1334 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));
1335 }
1336
1337 for (i = 0; i < ce->num_traits; i++) {
1338 if (ce->traits[i] == trait) {
1339 return;
1340 }
1341 }
1342 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
1343 }
1344 /* }}} */
1345
zend_traits_init_trait_structures(zend_class_entry * ce)1346 static void zend_traits_init_trait_structures(zend_class_entry *ce) /* {{{ */
1347 {
1348 size_t i, j = 0;
1349 zend_trait_precedence **precedences;
1350 zend_trait_precedence *cur_precedence;
1351 zend_trait_method_reference *cur_method_ref;
1352 zend_string *lcname;
1353 zend_bool method_exists;
1354
1355 /* resolve class references */
1356 if (ce->trait_precedences) {
1357 i = 0;
1358 precedences = ce->trait_precedences;
1359 ce->trait_precedences = NULL;
1360 while ((cur_precedence = precedences[i])) {
1361 /** Resolve classes for all precedence operations. */
1362 if (cur_precedence->exclude_from_classes) {
1363 cur_method_ref = cur_precedence->trait_method;
1364 if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
1365 ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1366 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1367 }
1368 zend_check_trait_usage(ce, cur_precedence->trait_method->ce);
1369
1370 /** Ensure that the preferred method is actually available. */
1371 lcname = zend_string_tolower(cur_method_ref->method_name);
1372 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
1373 lcname);
1374 zend_string_release(lcname);
1375 if (!method_exists) {
1376 zend_error_noreturn(E_COMPILE_ERROR,
1377 "A precedence rule was defined for %s::%s but this method does not exist",
1378 ZSTR_VAL(cur_method_ref->ce->name),
1379 ZSTR_VAL(cur_method_ref->method_name));
1380 }
1381
1382 /** With the other traits, we are more permissive.
1383 We do not give errors for those. This allows to be more
1384 defensive in such definitions.
1385 However, we want to make sure that the insteadof declaration
1386 is consistent in itself.
1387 */
1388 j = 0;
1389 while (cur_precedence->exclude_from_classes[j].class_name) {
1390 zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
1391
1392 if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1393 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
1394 }
1395 zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce);
1396
1397 /* make sure that the trait method is not from a class mentioned in
1398 exclude_from_classes, for consistency */
1399 if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[j].ce) {
1400 zend_error_noreturn(E_COMPILE_ERROR,
1401 "Inconsistent insteadof definition. "
1402 "The method %s is to be used from %s, but %s is also on the exclude list",
1403 ZSTR_VAL(cur_method_ref->method_name),
1404 ZSTR_VAL(cur_precedence->trait_method->ce->name),
1405 ZSTR_VAL(cur_precedence->trait_method->ce->name));
1406 }
1407
1408 zend_string_release(class_name);
1409 j++;
1410 }
1411 }
1412 i++;
1413 }
1414 ce->trait_precedences = precedences;
1415 }
1416
1417 if (ce->trait_aliases) {
1418 i = 0;
1419 while (ce->trait_aliases[i]) {
1420 /** For all aliases with an explicit class name, resolve the class now. */
1421 if (ce->trait_aliases[i]->trait_method->class_name) {
1422 cur_method_ref = ce->trait_aliases[i]->trait_method;
1423 if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD))) {
1424 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1425 }
1426 zend_check_trait_usage(ce, cur_method_ref->ce);
1427
1428 /** And, ensure that the referenced method is resolvable, too. */
1429 lcname = zend_string_tolower(cur_method_ref->method_name);
1430 method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
1431 lcname);
1432 zend_string_release(lcname);
1433
1434 if (!method_exists) {
1435 zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(cur_method_ref->ce->name), ZSTR_VAL(cur_method_ref->method_name));
1436 }
1437 }
1438 i++;
1439 }
1440 }
1441 }
1442 /* }}} */
1443
zend_traits_compile_exclude_table(HashTable * exclude_table,zend_trait_precedence ** precedences,zend_class_entry * trait)1444 static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
1445 {
1446 size_t i = 0, j;
1447
1448 if (!precedences) {
1449 return;
1450 }
1451 while (precedences[i]) {
1452 if (precedences[i]->exclude_from_classes) {
1453 j = 0;
1454 while (precedences[i]->exclude_from_classes[j].ce) {
1455 if (precedences[i]->exclude_from_classes[j].ce == trait) {
1456 zend_string *lcname =
1457 zend_string_tolower(precedences[i]->trait_method->method_name);
1458 if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
1459 zend_string_release(lcname);
1460 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(trait->name));
1461 }
1462 zend_string_release(lcname);
1463 }
1464 ++j;
1465 }
1466 }
1467 ++i;
1468 }
1469 }
1470 /* }}} */
1471
zend_do_traits_method_binding(zend_class_entry * ce)1472 static void zend_do_traits_method_binding(zend_class_entry *ce) /* {{{ */
1473 {
1474 uint32_t i;
1475 HashTable *overriden = NULL;
1476 zend_string *key;
1477 zend_function *fn;
1478
1479 for (i = 0; i < ce->num_traits; i++) {
1480 if (ce->trait_precedences) {
1481 HashTable exclude_table;
1482 zend_trait_precedence **precedences;
1483
1484 /* TODO: revisit this start size, may be its not optimal */
1485 zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
1486
1487 precedences = ce->trait_precedences;
1488 ce->trait_precedences = NULL;
1489 zend_traits_compile_exclude_table(&exclude_table, precedences, ce->traits[i]);
1490
1491 /* copies functions, applies defined aliasing, and excludes unused trait methods */
1492 ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
1493 zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table);
1494 } ZEND_HASH_FOREACH_END();
1495
1496 zend_hash_destroy(&exclude_table);
1497 ce->trait_precedences = precedences;
1498 } else {
1499 ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
1500 zend_traits_copy_functions(key, fn, ce, &overriden, NULL);
1501 } ZEND_HASH_FOREACH_END();
1502 }
1503 }
1504
1505 ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
1506 zend_fixup_trait_method(fn, ce);
1507 } ZEND_HASH_FOREACH_END();
1508
1509 if (ce->trait_precedences) {
1510 i = 0;
1511 while (ce->trait_precedences[i]) {
1512 if (ce->trait_precedences[i]->exclude_from_classes) {
1513 efree(ce->trait_precedences[i]->exclude_from_classes);
1514 ce->trait_precedences[i]->exclude_from_classes = NULL;
1515 }
1516 i++;
1517 }
1518 }
1519
1520 if (overriden) {
1521 zend_hash_destroy(overriden);
1522 FREE_HASHTABLE(overriden);
1523 }
1524 }
1525 /* }}} */
1526
find_first_definition(zend_class_entry * ce,size_t current_trait,zend_string * prop_name,zend_class_entry * coliding_ce)1527 static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
1528 {
1529 size_t i;
1530
1531 if (coliding_ce == ce) {
1532 for (i = 0; i < current_trait; i++) {
1533 if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
1534 return ce->traits[i];
1535 }
1536 }
1537 }
1538
1539 return coliding_ce;
1540 }
1541 /* }}} */
1542
zend_do_traits_property_binding(zend_class_entry * ce)1543 static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */
1544 {
1545 size_t i;
1546 zend_property_info *property_info;
1547 zend_property_info *coliding_prop;
1548 zval compare_result;
1549 zend_string* prop_name;
1550 const char* class_name_unused;
1551 zend_bool not_compatible;
1552 zval* prop_value;
1553 uint32_t flags;
1554 zend_string *doc_comment;
1555
1556 /* In the following steps the properties are inserted into the property table
1557 * for that, a very strict approach is applied:
1558 * - check for compatibility, if not compatible with any property in class -> fatal
1559 * - if compatible, then strict notice
1560 */
1561 for (i = 0; i < ce->num_traits; i++) {
1562 ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
1563 /* first get the unmangeld name if necessary,
1564 * then check whether the property is already there
1565 */
1566 flags = property_info->flags;
1567 if (flags & ZEND_ACC_PUBLIC) {
1568 prop_name = zend_string_copy(property_info->name);
1569 } else {
1570 const char *pname;
1571 size_t pname_len;
1572
1573 /* for private and protected we need to unmangle the names */
1574 zend_unmangle_property_name_ex(property_info->name,
1575 &class_name_unused, &pname, &pname_len);
1576 prop_name = zend_string_init(pname, pname_len, 0);
1577 }
1578
1579 /* next: check for conflicts with current class */
1580 if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
1581 if (coliding_prop->flags & ZEND_ACC_SHADOW) {
1582 zend_string_release(coliding_prop->name);
1583 if (coliding_prop->doc_comment) {
1584 zend_string_release(coliding_prop->doc_comment);
1585 }
1586 zend_hash_del(&ce->properties_info, prop_name);
1587 flags |= ZEND_ACC_CHANGED;
1588 } else {
1589 if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
1590 == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
1591 /* flags are identical, now the value needs to be checked */
1592 if (flags & ZEND_ACC_STATIC) {
1593 not_compatible = (FAILURE == compare_function(&compare_result,
1594 &ce->default_static_members_table[coliding_prop->offset],
1595 &ce->traits[i]->default_static_members_table[property_info->offset]))
1596 || (Z_LVAL(compare_result) != 0);
1597 } else {
1598 not_compatible = (FAILURE == compare_function(&compare_result,
1599 &ce->default_properties_table[OBJ_PROP_TO_NUM(coliding_prop->offset)],
1600 &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]))
1601 || (Z_LVAL(compare_result) != 0);
1602 }
1603 } else {
1604 /* the flags are not identical, thus, we assume properties are not compatible */
1605 not_compatible = 1;
1606 }
1607
1608 if (not_compatible) {
1609 zend_error_noreturn(E_COMPILE_ERROR,
1610 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
1611 ZSTR_VAL(find_first_definition(ce, i, prop_name, coliding_prop->ce)->name),
1612 ZSTR_VAL(property_info->ce->name),
1613 ZSTR_VAL(prop_name),
1614 ZSTR_VAL(ce->name));
1615 }
1616
1617 zend_string_release(prop_name);
1618 continue;
1619 }
1620 }
1621
1622 /* property not found, so lets add it */
1623 if (flags & ZEND_ACC_STATIC) {
1624 prop_value = &ce->traits[i]->default_static_members_table[property_info->offset];
1625 } else {
1626 prop_value = &ce->traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
1627 }
1628 if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
1629
1630 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
1631 zend_declare_property_ex(ce, prop_name,
1632 prop_value, flags,
1633 doc_comment);
1634 zend_string_release(prop_name);
1635 } ZEND_HASH_FOREACH_END();
1636 }
1637 }
1638 /* }}} */
1639
zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry * ce)1640 static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce) /* {{{ */
1641 {
1642 int i = 0;
1643 zend_trait_alias* cur_alias;
1644 zend_string* lc_method_name;
1645
1646 if (ce->trait_aliases) {
1647 while (ce->trait_aliases[i]) {
1648 cur_alias = ce->trait_aliases[i];
1649 /** The trait for this alias has not been resolved, this means, this
1650 alias was not applied. Abort with an error. */
1651 if (!cur_alias->trait_method->ce) {
1652 if (cur_alias->alias) {
1653 /** Plain old inconsistency/typo/bug */
1654 zend_error_noreturn(E_COMPILE_ERROR,
1655 "An alias (%s) was defined for method %s(), but this method does not exist",
1656 ZSTR_VAL(cur_alias->alias),
1657 ZSTR_VAL(cur_alias->trait_method->method_name));
1658 } else {
1659 /** Here are two possible cases:
1660 1) this is an attempt to modifiy the visibility
1661 of a method introduce as part of another alias.
1662 Since that seems to violate the DRY principle,
1663 we check against it and abort.
1664 2) it is just a plain old inconsitency/typo/bug
1665 as in the case where alias is set. */
1666
1667 lc_method_name = zend_string_tolower(
1668 cur_alias->trait_method->method_name);
1669 if (zend_hash_exists(&ce->function_table,
1670 lc_method_name)) {
1671 zend_string_release(lc_method_name);
1672 zend_error_noreturn(E_COMPILE_ERROR,
1673 "The modifiers for the trait alias %s() need to be changed in the same statement in which the alias is defined. Error",
1674 ZSTR_VAL(cur_alias->trait_method->method_name));
1675 } else {
1676 zend_string_release(lc_method_name);
1677 zend_error_noreturn(E_COMPILE_ERROR,
1678 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
1679 ZSTR_VAL(cur_alias->trait_method->method_name));
1680
1681 }
1682 }
1683 }
1684 i++;
1685 }
1686 }
1687 }
1688 /* }}} */
1689
zend_do_bind_traits(zend_class_entry * ce)1690 ZEND_API void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
1691 {
1692
1693 if (ce->num_traits <= 0) {
1694 return;
1695 }
1696
1697 /* complete initialization of trait strutures in ce */
1698 zend_traits_init_trait_structures(ce);
1699
1700 /* first care about all methods to be flattened into the class */
1701 zend_do_traits_method_binding(ce);
1702
1703 /* Aliases which have not been applied indicate typos/bugs. */
1704 zend_do_check_for_inconsistent_traits_aliasing(ce);
1705
1706 /* then flatten the properties into it, to, mostly to notfiy developer about problems */
1707 zend_do_traits_property_binding(ce);
1708
1709 /* verify that all abstract methods from traits have been implemented */
1710 zend_verify_abstract_class(ce);
1711
1712 /* Emit E_DEPRECATED for PHP 4 constructors */
1713 zend_check_deprecated_constructor(ce);
1714
1715 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
1716 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1717 ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1718 }
1719 }
1720 /* }}} */
1721
1722
zend_has_deprecated_constructor(const zend_class_entry * ce)1723 static zend_bool zend_has_deprecated_constructor(const zend_class_entry *ce) /* {{{ */
1724 {
1725 const zend_string *constructor_name;
1726 if (!ce->constructor) {
1727 return 0;
1728 }
1729 constructor_name = ce->constructor->common.function_name;
1730 return !zend_binary_strcasecmp(
1731 ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
1732 ZSTR_VAL(constructor_name), ZSTR_LEN(constructor_name)
1733 );
1734 }
1735 /* }}} */
1736
zend_check_deprecated_constructor(const zend_class_entry * ce)1737 void zend_check_deprecated_constructor(const zend_class_entry *ce) /* {{{ */
1738 {
1739 if (zend_has_deprecated_constructor(ce)) {
1740 zend_error(E_DEPRECATED, "Methods with the same name as their class will not be constructors in a future version of PHP; %s has a deprecated constructor", ZSTR_VAL(ce->name));
1741 }
1742 }
1743 /* }}} */
1744
1745 /*
1746 * Local variables:
1747 * tab-width: 4
1748 * c-basic-offset: 4
1749 * indent-tabs-mode: t
1750 * End:
1751 */
1752