![]() |
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
Patch __CLASS__-in-traits.patch for Scripting Engine problem Bug #55214Patch version 2011-07-23 17:45 UTC Return to Bug #55214 | Download this patchThis patch is obsolete Obsoleted by patches: Patch Revisions:Developer: gron@php.netIndex: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 313635) +++ Zend/zend_compile.c (working copy) @@ -3482,7 +3482,7 @@ /* {{{ Originates from php_runkit_function_copy_ctor Duplicate structures in an op_array where necessary to make an outright duplicate */ -static void zend_traits_duplicate_function(zend_function *fe, char *newname TSRMLS_DC) +static void zend_traits_duplicate_function(zend_function *fe, zend_class_entry *target_ce, char *newname TSRMLS_DC) { zend_literal *literals_copy; zend_compiled_variable *dupvars; @@ -3520,14 +3525,27 @@ opcode_copy[i].op1.jmp_addr < fe->op_array.opcodes + fe->op_array.last) { opcode_copy[i].op1.jmp_addr = opcode_copy + (fe->op_array.opcodes[i].op1.jmp_addr - fe->op_array.opcodes); } - } + } else { + // if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here + if (target_ce && Z_TYPE_P(opcode_copy[i].op1.zv) == IS_NULL && Z_LVAL_P(opcode_copy[i].op1.zv) == ZEND_ACC_TRAIT) { + ALLOC_INIT_ZVAL(opcode_copy[i].op1.zv); + ZVAL_STRINGL(opcode_copy[i].op1.zv, target_ce->name, target_ce->name_length, 0); + } + } + if (opcode_copy[i].op2_type != IS_CONST) { if (opcode_copy[i].op2.jmp_addr >= fe->op_array.opcodes && opcode_copy[i].op2.jmp_addr < fe->op_array.opcodes + fe->op_array.last) { opcode_copy[i].op2.jmp_addr = opcode_copy + (fe->op_array.opcodes[i].op2.jmp_addr - fe->op_array.opcodes); } - } + } else { + // if __CLASS__ i.e. T_CLASS_C was used, we need to fix it up here + if (target_ce && Z_TYPE_P(opcode_copy[i].op2.zv) == IS_NULL && Z_LVAL_P(opcode_copy[i].op2.zv) == ZEND_ACC_TRAIT) { + ALLOC_INIT_ZVAL(opcode_copy[i].op2.zv); + ZVAL_STRINGL(opcode_copy[i].op2.zv, target_ce->name, target_ce->name_length, 0); + } + } } fe->op_array.opcodes = opcode_copy; fe->op_array.function_name = newname; @@ -3614,7 +3632,7 @@ ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; } fn_copy = *fn; - zend_traits_duplicate_function(&fn_copy, estrdup(fn->common.function_name) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, ce, estrdup(fn->common.function_name) TSRMLS_CC); if (zend_hash_quick_update(&ce->function_table, hash_key->arKey, hash_key->nKeyLength, hash_key->h, &fn_copy, sizeof(zend_function), (void**)&fn_copy_p)==FAILURE) { zend_error(E_COMPILE_ERROR, "Trait method %s has not been applied, because failure occured during updating class method table", hash_key->arKey); @@ -3636,6 +3654,7 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { HashTable* target; + zend_class_entry *target_ce; zend_trait_alias** aliases; HashTable* exclude_table; char* lcname; @@ -3643,7 +3662,9 @@ zend_function fn_copy; void* dummy; size_t i = 0; + target = va_arg(args, HashTable*); + target_ce = va_arg(args, zend_class_entry*); aliases = va_arg(args, zend_trait_alias**); exclude_table = va_arg(args, HashTable*); @@ -3658,7 +3679,7 @@ && aliases[i]->trait_method->mname_len == fnname_len && (zend_binary_strcasecmp(aliases[i]->trait_method->method_name, aliases[i]->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) { fn_copy = *fn; - zend_traits_duplicate_function(&fn_copy, estrndup(aliases[i]->alias, aliases[i]->alias_len) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, NULL, estrndup(aliases[i]->alias, aliases[i]->alias_len) TSRMLS_CC); /* if it is 0, no modifieres has been changed */ if (aliases[i]->modifiers) { @@ -3685,7 +3706,7 @@ if (exclude_table == NULL || zend_hash_find(exclude_table, lcname, fnname_len, &dummy) == FAILURE) { /* is not in hashtable, thus, function is not to be excluded */ fn_copy = *fn; - zend_traits_duplicate_function(&fn_copy, estrndup(fn->common.function_name, fnname_len) TSRMLS_CC); + zend_traits_duplicate_function(&fn_copy, NULL, estrndup(fn->common.function_name, fnname_len) TSRMLS_CC); /* apply aliases which are not qualified by a class name, or which have not * alias name, just setting visibility */ @@ -3720,9 +3741,9 @@ /* }}} */ /* Copies function table entries to target function table with applied aliasing */ -static void zend_traits_copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */ +static void zend_traits_copy_trait_function_table(HashTable *target, zend_class_entry *target_ce, HashTable *source, zend_trait_alias** aliases, HashTable* exclude_table TSRMLS_DC) /* {{{ */ { - zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, target, aliases, exclude_table); + zend_hash_apply_with_arguments(source TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 4, target, target_ce, aliases, exclude_table); } /* }}} */ @@ -3820,10 +3841,10 @@ zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]); /* copies functions, applies defined aliasing, and excludes unused trait methods */ - zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC); + zend_traits_copy_trait_function_table(function_tables[i], ce, &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table TSRMLS_CC); zend_hash_graceful_destroy(&exclude_table); } else { - zend_traits_copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC); + zend_traits_copy_trait_function_table(function_tables[i], ce, &ce->traits[i]->function_table, ce->trait_aliases, NULL TSRMLS_CC); } } Index: Zend/zend_language_scanner.l =================================================================== --- Zend/zend_language_scanner.l (revision 313635) +++ Zend/zend_language_scanner.l (working copy) @@ -1529,16 +1529,25 @@ <ST_IN_SCRIPTING>"__CLASS__" { char *class_name = NULL; - if (CG(active_class_entry)) { - class_name = CG(active_class_entry)->name; - } + if (ZEND_ACC_TRAIT == (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT)) { + // This is a hack, we abuse IS_NULL to indicate an invalid value + // if __CLASS__ is encountered in a trait, however, we also not that we + // should fix it up when we copy the method into an actual class + zendlval->value.lval = ZEND_ACC_TRAIT; + zendlval->type = IS_NULL; + } else { + if (CG(active_class_entry)) { + class_name = CG(active_class_entry)->name; + } - if (!class_name) { - class_name = ""; + if (!class_name) { + class_name = ""; + } + + zendlval->value.str.len = strlen(class_name); + zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); + zendlval->type = IS_STRING; } - zendlval->value.str.len = strlen(class_name); - zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); - zendlval->type = IS_STRING; return T_CLASS_C; } |
![]() All rights reserved. |
Last updated: Wed Feb 19 02:01:29 2025 UTC |