root/Zend/zend_inheritance.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. overriden_ptr_dtor
  2. zend_duplicate_property_info
  3. zend_duplicate_property_info_internal
  4. zend_duplicate_function
  5. do_inherit_parent_constructor
  6. zend_visibility_string
  7. zend_do_perform_type_hint_check
  8. zend_do_perform_implementation_check
  9. zend_append_type_hint
  10. zend_get_function_declaration
  11. do_inheritance_check_on_method
  12. do_inherit_method
  13. do_inherit_property
  14. do_implement_interface
  15. zend_do_inherit_interfaces
  16. do_inherit_class_constant
  17. zend_do_inheritance
  18. do_inherit_constant_check
  19. do_inherit_iface_constant
  20. zend_do_implement_interface
  21. zend_do_implement_trait
  22. zend_traits_method_compatibility_check
  23. zend_add_magic_methods
  24. zend_add_trait_method
  25. zend_fixup_trait_method
  26. zend_traits_copy_functions
  27. zend_check_trait_usage
  28. zend_traits_init_trait_structures
  29. zend_traits_compile_exclude_table
  30. zend_do_traits_method_binding
  31. find_first_definition
  32. zend_do_traits_property_binding
  33. zend_do_check_for_inconsistent_traits_aliasing
  34. zend_do_bind_traits
  35. zend_has_deprecated_constructor
  36. zend_check_deprecated_constructor

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

/* [<][>][^][v][top][bottom][index][help] */