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 #55214

Patch version 2011-07-23 17:45 UTC

Return to Bug #55214 | Download this patch
This 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;
 }
 
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 23 20:01:29 2024 UTC