|
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.net
Index: 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;
}
|
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Oct 24 17:00:01 2025 UTC |