? Zend/.svn
? Zend/tests/.svn
? Zend/tests/traits
Index: Zend/zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.293.2.11.2.11
diff -u -r1.293.2.11.2.11 zend.h
--- Zend/zend.h	15 Feb 2008 07:44:45 -0000	1.293.2.11.2.11
+++ Zend/zend.h	16 Feb 2008 21:03:14 -0000
@@ -22,7 +22,7 @@
 #ifndef ZEND_H
 #define ZEND_H
 
-#define ZEND_VERSION "2.2.0"
+#define ZEND_VERSION "2.2.0-with-traits"
 
 #define ZEND_ENGINE_2
 
@@ -327,6 +327,30 @@
 typedef struct _zend_serialize_data zend_serialize_data;
 typedef struct _zend_unserialize_data zend_unserialize_data;
 
+struct _zend_trait_alias {
+	/**
+	* name of method to be renamed
+	*/
+	char* method_name;
+	
+	/**
+	* new name for method
+	*/
+	char* alias;
+	
+	/**
+	* modifiers to be set on trait method
+	*/
+	zend_uint modifiers;
+	
+	/**
+	*
+	*/
+	union _zend_function* function;
+};
+
+typedef struct _zend_trait_alias zend_trait_alias;
+
 struct _zend_class_entry {
 	char type;
 	char *name;
@@ -369,6 +393,11 @@
 
 	zend_class_entry **interfaces;
 	zend_uint num_interfaces;
+	
+	// STEFAN ADDED for Traits
+	zend_class_entry **traits;
+	zend_uint num_traits;
+	zend_trait_alias*** trait_aliases;
 
 	char *filename;
 	zend_uint line_start;
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.296.2.27.2.36
diff -u -r1.296.2.27.2.36 zend_API.c
--- Zend/zend_API.c	15 Feb 2008 07:44:45 -0000	1.296.2.27.2.36
+++ Zend/zend_API.c	16 Feb 2008 21:03:15 -0000
@@ -931,7 +931,7 @@
 	zval *tmp;
 	zend_object *object;
 
-	if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
+	if (class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_TRAIT)) {
 		char *what = class_type->ce_flags & ZEND_ACC_INTERFACE ? "interface" : "abstract class";
 		zend_error(E_ERROR, "Cannot instantiate %s %s", what, class_type->name);
 	}
@@ -1700,7 +1700,7 @@
 				if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
 					/* Since the class is not an interface it needs to be declared as a abstract class. */
 					/* Since here we are handling internal functions only we can add the keyword flag. */
-					/* This time we set the flag for the keyword 'abstratc'. */
+					/* This time we set the flag for the keyword 'abstract'. */
 					scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
 				}
 			}
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.47
diff -u -r1.647.2.27.2.47 zend_compile.c
--- Zend/zend_compile.c	15 Feb 2008 07:44:45 -0000	1.647.2.27.2.47
+++ Zend/zend_compile.c	16 Feb 2008 21:03:17 -0000
@@ -332,6 +332,50 @@
 	*result = opline->result;
 }
 
+void add_trait_alias(znode* result, znode* trait_alias TSRMLS_DC)
+{
+	zend_trait_alias** aliases = (zend_trait_alias**)result->u.var;
+	size_t count = 0;
+	
+	while (aliases[count]) {
+		count++;
+	}
+	
+	aliases = erealloc(aliases, sizeof(zend_trait_alias*)*(count+2));
+	aliases[count + 1] = NULL;	// it is a list without length but NULL as last element
+	aliases[count] = trait_alias->u.var;
+	
+	result->u.var = aliases;
+}
+
+void init_trait_alias(znode* result, znode* method_name, znode* alias, znode* modifiers TSRMLS_DC)
+{
+	zend_trait_alias* trait_alias = emalloc(sizeof(zend_trait_alias));
+	trait_alias->method_name = Z_STRVAL(method_name->u.constant);
+	
+	// may be method is only excluded, then the alias node is NULL
+	if (alias) {
+		trait_alias->alias = Z_STRVAL(alias->u.constant);
+		trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
+	} else {
+		trait_alias->alias = NULL;
+		trait_alias->modifiers = 0;
+	}
+	trait_alias->function = NULL;
+	
+	
+	result->u.var = trait_alias;
+}
+
+void init_trait_alias_list(znode* result, znode* trait_alias TSRMLS_DC)
+{
+	zend_trait_alias** aliases = emalloc(sizeof(zend_trait_alias*) * 2);
+	aliases[1] = NULL;	// it is a list without length but NULL as last element
+	aliases[0] = trait_alias->u.var;
+	
+	result->u.var = aliases;
+}
+
 void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC)
 {
 	zend_op opline;
@@ -2327,7 +2371,6 @@
 	return 1;
 }
 
-
 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC)
 {
 	zend_uint i, ignore = 0;
@@ -2357,13 +2400,379 @@
 		ce->interfaces[ce->num_interfaces++] = iface;
 	
 		zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
-		zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
+		
+		if (!(ce->ce_flags & ZEND_ACC_TRAIT)) {
+			zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
+		}
 	
 		do_implement_interface(ce, iface TSRMLS_CC);
 		zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
 	}
 }
 
+ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait, zend_trait_alias** aliases TSRMLS_DC)
+{
+	/* just add trait to list of traits, all magic is done on class binding */
+	zend_uint new_trait_count = ce->num_traits + 1;
+	if (ce->type == ZEND_INTERNAL_CLASS) {
+		ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * new_trait_count);
+		ce->trait_aliases = (zend_trait_alias ***) realloc(ce->trait_aliases, sizeof(zend_trait_alias **) * new_trait_count);
+	} else {
+		ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * new_trait_count);
+		ce->trait_aliases = (zend_trait_alias ***) erealloc(ce->trait_aliases, sizeof(zend_trait_alias **) * new_trait_count);
+	}
+	ce->traits[ce->num_traits] = trait;
+	ce->trait_aliases[ce->num_traits] = aliases;
+	ce->num_traits++;
+}
+
+static int _merge_functions(zend_function *fn, int num_args, va_list args, zend_hash_key *hash_key)
+{
+	size_t current;
+	size_t i;
+	size_t count;
+	HashTable* resulting_table;
+	HashTable** function_tables;
+	zend_class_entry *ce;
+	char* lcname;
+	size_t collision = 0;
+	size_t abstract_solved = 0;
+	size_t name_len;
+	zend_function* other_trait_fn;
+
+	current			= va_arg(args, size_t);  // index of current trait
+	count			= va_arg(args, size_t);
+	resulting_table = va_arg(args, HashTable*);
+	function_tables = va_arg(args, HashTable**);
+	ce				= va_arg(args, zend_class_entry*);
+	
+	name_len = strlen(hash_key->arKey); //hash_key->nKeyLength;
+	lcname = zend_str_tolower_dup(hash_key->arKey, name_len);
+	
+	for (i = 0; i < count; i++) {
+		if (i == current) {
+			continue; // just skip this, cause its the table this function is applied on
+		}
+		
+		if (zend_hash_find(function_tables[i], lcname, name_len + 1, &other_trait_fn) == SUCCESS) {
+			// if it is an abstract method, there is no collision
+			if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+				// we can savely free and remove it from other table
+				zend_function_dtor(other_trait_fn);
+				zend_hash_del(function_tables[i], lcname, name_len + 1);
+				//efree(other_trait_fn);
+			} else {
+				// if it is not an abstract method, there is still no collision
+				// iff fn is an abstract method
+				if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+					// just mark as solved, will be added if its own trait is processed
+					abstract_solved = 1;
+				} else {
+					// but else, we have a collision of non-abstract methods
+					collision++;
+					zend_function_dtor(other_trait_fn);
+					zend_hash_del(function_tables[i], lcname, name_len + 1);
+				}
+			}
+		}
+	}
+	
+	if (collision) {
+		zend_function* class_fn;
+		// make sure method is not already overridden in class
+		
+		if (zend_hash_find(&ce->function_table, lcname, name_len + 1, &class_fn) == FAILURE
+			|| class_fn->common.scope != ce) {
+				zend_error(E_WARNING, "Trait method %s has not been applied, because there are collisions with other trait methods on %s", fn->common.function_name, ce->name);
+		}
+		
+		zend_function_dtor(fn);
+	} else if (abstract_solved) {
+		zend_function_dtor(fn);
+	} else {
+		// Add it to result function table
+		if (zend_hash_add(resulting_table, lcname, name_len + 1, fn, sizeof(zend_function), NULL)==FAILURE) {
+			zend_error(E_ERROR, "Trait method %s has not been applied, because failure occured during updating resulting trait method table.", fn->common.function_name);
+		}
+	}
+	
+	efree(lcname);
+	return ZEND_HASH_APPLY_REMOVE;
+}
+
+#define PHP_RUNKIT_ADD_MAGIC_METHOD(ce, method, fe) { \
+	if ((strcmp((method), (ce)->name) == 0) || \
+		(strcmp((method), "__construct") == 0)) {	(ce)->constructor	= (fe); (fe)->common.fn_flags = ZEND_ACC_CTOR; } \
+	else if (strcmp((method), "__destruct") == 0) {	(ce)->destructor	= (fe); (fe)->common.fn_flags = ZEND_ACC_DTOR; } \
+	else if (strcmp((method), "__clone") == 0)  {	(ce)->clone			= (fe); (fe)->common.fn_flags = ZEND_ACC_CLONE; } \
+	else if (strcmp((method), "__get") == 0)		(ce)->__get			= (fe); \
+	else if (strcmp((method), "__set") == 0)		(ce)->__set			= (fe); \
+	else if (strcmp((method), "__call") == 0)		(ce)->__call		= (fe); \
+}
+
+/* {{{ php_runkit_function_copy_ctor
+	Duplicate structures in an op_array where necessary to make an outright duplicate */
+void php_runkit_function_copy_ctor(zend_function *fe, char *newname)
+{
+//#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)
+	zend_compiled_variable *dupvars;
+//#endif
+	zend_op *opcode_copy;
+	int i;
+
+	if (fe->op_array.static_variables) {
+		HashTable *tmpHash;
+		zval tmpZval;
+
+		ALLOC_HASHTABLE(tmpHash);
+		zend_hash_init(tmpHash, 2, NULL, ZVAL_PTR_DTOR, 0);
+		zend_hash_copy(tmpHash, fe->op_array.static_variables, ZVAL_COPY_CTOR, &tmpZval, sizeof(zval));
+		fe->op_array.static_variables = tmpHash;
+	}
+
+	fe->op_array.refcount = emalloc(sizeof(zend_uint));
+	*(fe->op_array.refcount) = 1;
+
+	i = fe->op_array.last_var;
+	dupvars = safe_emalloc(fe->op_array.last_var, sizeof(zend_compiled_variable), 0);
+	while (i > 0) {
+		i--;
+		dupvars[i].name = estrdup(fe->op_array.vars[i].name);
+		dupvars[i].name_len = fe->op_array.vars[i].name_len;
+		dupvars[i].hash_value = fe->op_array.vars[i].hash_value;
+	}
+	fe->op_array.vars = dupvars;
+
+	opcode_copy = safe_emalloc(sizeof(zend_op), fe->op_array.last, 0);
+	for(i = 0; i < fe->op_array.last; i++) {
+		opcode_copy[i] = fe->op_array.opcodes[i];
+		if (opcode_copy[i].op1.op_type == IS_CONST) {
+			zval_copy_ctor(&opcode_copy[i].op1.u.constant);
+		} else {
+			if (opcode_copy[i].op1.u.jmp_addr >= fe->op_array.opcodes &&
+				opcode_copy[i].op1.u.jmp_addr <  fe->op_array.opcodes + fe->op_array.last) {
+				opcode_copy[i].op1.u.jmp_addr =  opcode_copy + (fe->op_array.opcodes[i].op1.u.jmp_addr - fe->op_array.opcodes);
+			}
+                }
+
+		if (opcode_copy[i].op2.op_type == IS_CONST) {
+			zval_copy_ctor(&opcode_copy[i].op2.u.constant);
+		} else {
+			if (opcode_copy[i].op2.u.jmp_addr >= fe->op_array.opcodes &&
+				opcode_copy[i].op2.u.jmp_addr <  fe->op_array.opcodes + fe->op_array.last) {
+				opcode_copy[i].op2.u.jmp_addr =  opcode_copy + (fe->op_array.opcodes[i].op2.u.jmp_addr - fe->op_array.opcodes);
+			}
+		}
+	}
+	fe->op_array.opcodes = opcode_copy;
+	fe->op_array.start_op = fe->op_array.opcodes;
+
+	if (newname) {
+		fe->op_array.function_name = newname;
+	} else {
+		fe->op_array.function_name = estrdup(fe->op_array.function_name);
+	}
+
+	fe->op_array.prototype = fe;
+
+	if (fe->op_array.arg_info) {
+		zend_arg_info *tmpArginfo;
+
+		tmpArginfo = safe_emalloc(sizeof(zend_arg_info), fe->op_array.num_args, 0);
+		for(i = 0; i < fe->op_array.num_args; i++) {
+			tmpArginfo[i] = fe->op_array.arg_info[i];
+			tmpArginfo[i].name = estrndup(tmpArginfo[i].name, tmpArginfo[i].name_len);
+			if (tmpArginfo[i].class_name) {
+				tmpArginfo[i].class_name = estrndup(tmpArginfo[i].class_name, tmpArginfo[i].class_name_len);
+			}
+		}
+		fe->op_array.arg_info = tmpArginfo;
+	}
+
+	fe->op_array.doc_comment = estrndup(fe->op_array.doc_comment, fe->op_array.doc_comment_len);
+	fe->op_array.try_catch_array = (zend_try_catch_element*)estrndup((char*)fe->op_array.try_catch_array, sizeof(zend_try_catch_element) * fe->op_array.last_try_catch);
+
+	fe->op_array.brk_cont_array = (zend_brk_cont_element*)estrndup((char*)fe->op_array.brk_cont_array, sizeof(zend_brk_cont_element) * fe->op_array.last_brk_cont);
+}
+/* }}}} */
+
+static int _merge_functions_to_class(zend_function *fn, int num_args, va_list args, zend_hash_key *hash_key TSRMLS_DC)
+{
+	zend_class_entry *ce = va_arg(args, zend_class_entry*);
+	size_t name_len = strlen(hash_key->arKey); //hash_key->nKeyLength; //strlen(fn->common.function_name);
+	char* lcname = zend_str_tolower_dup(hash_key->arKey, name_len);
+	int add = 0;	
+	zend_function* existing_fn;
+	
+	if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void**) &existing_fn) == FAILURE) {
+		add = 1; // not found
+	} else if (existing_fn->common.scope != ce) {
+		add = 1; // or inherited from other class
+		zend_hash_del(&ce->function_table, lcname, name_len + 1);
+	} 
+	
+	if (add) {
+#ifdef ZEND_ENGINE_2
+		fn->common.scope = ce;
+#endif
+		// remove ZEND_ACC_IMPLEMENTED_ABSTRACT flag, think it shouldn't be copied to class
+		if (fn->common.fn_flags & ZEND_ACC_IMPLEMENTED_ABSTRACT) {
+			fn->common.fn_flags = fn->common.fn_flags - ZEND_ACC_IMPLEMENTED_ABSTRACT;
+		}
+
+		if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
+			ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
+		}
+
+		if (zend_hash_add(&ce->function_table, lcname, name_len + 1, fn, sizeof(zend_function), NULL)==FAILURE) {
+			zend_error(E_ERROR, "Trait method %s has not been applied, because failure occured during updating class method table.", hash_key->arKey);
+		}
+		
+		PHP_RUNKIT_ADD_MAGIC_METHOD(ce, lcname, fn);
+		//it could be necessary to update child classes as well
+		//zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t)php_runkit_update_children_methods, 5, dce, dce, &dfe, dfunc, dfunc_len);
+	} else {
+		zend_function_dtor(fn);
+		//efree(fn);
+	}
+	
+	efree(lcname);
+	return ZEND_HASH_APPLY_REMOVE;
+}
+
+static int _copy_functions(zend_function *fn, int num_args, va_list args, zend_hash_key *hash_key)
+{
+	HashTable* target;
+	zend_trait_alias** aliases;
+	char* lcname;
+	zend_function fn_copy;
+	
+	size_t i = 0;
+	size_t excluded = 0;
+	size_t name_len;
+	
+	target = va_arg(args, HashTable*);
+	aliases = va_arg(args, zend_trait_alias**);
+
+	if (aliases) {
+		while (aliases[i]) {
+			if (strcasecmp(aliases[i]->method_name, fn->common.function_name) == 0) {
+				if (aliases[i]->alias) { //if alias is NULL, method should be excluded, so its not added
+					//fn_copy = emalloc(sizeof(zend_function));
+					fn_copy = *fn;
+					name_len = strlen(aliases[i]->alias);
+					php_runkit_function_copy_ctor(&fn_copy, estrndup(aliases[i]->alias, name_len));
+
+					if (aliases[i]->modifiers) { // if it is 0, no modifieres has been changed
+						fn_copy.common.fn_flags = aliases[i]->modifiers;
+						if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
+							fn_copy.common.fn_flags |= ZEND_ACC_PUBLIC;
+						}
+					}
+
+					lcname = zend_str_tolower_dup(fn_copy.common.function_name, name_len);
+
+					if (zend_hash_add(target, lcname, name_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
+						zend_error(E_ERROR, "Failed to added aliased trait method (%s) to trait table. Propably there is already a trait method with same name\n", fn_copy.common.function_name);
+					}
+					//aliases[i]->function = fn_copy;
+					efree(lcname);
+				} else {
+					excluded = 1;
+				}
+			}
+			i++;
+		}
+	}
+	
+	if (!excluded) {
+		//fn_copy = emalloc(sizeof(zend_function));
+		fn_copy = *fn;
+		name_len = strlen(fn->common.function_name);
+		php_runkit_function_copy_ctor(&fn_copy, estrndup(fn->common.function_name, name_len));
+		lcname = zend_str_tolower_dup(fn->common.function_name, name_len);
+
+		if (zend_hash_add(target, lcname, name_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
+			zend_error(E_ERROR, "Failed to added trait method (%s) to trait table. Propably there is already a trait method with same name\n", fn_copy.common.function_name);
+		}
+		efree(lcname);
+	}
+	return ZEND_HASH_APPLY_KEEP;
+}
+
+/**
+* Copies function table entries to target function table with applied aliasing
+*/
+void copy_trait_function_table(HashTable *target, HashTable *source, zend_trait_alias** aliases) {
+	zend_hash_apply_with_arguments(source, (apply_func_args_t)_copy_functions, 2, //2 is number of args for apply_func
+			target, aliases);
+}
+
+ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC)
+{
+	size_t i, j;
+	//zend_function tmp_func;
+	HashTable** function_tables;
+	HashTable* resulting_table;
+	
+	if (ce->num_traits <= 0) { return; }
+	
+	//printf("Do bind Traits on %s with %d traits.\n Class has already %d methods.\n",
+	//	   ce->name, ce->num_traits, ce->function_table.nNumOfElements);
+	
+	// prepare copies of trait function tables for combination
+	function_tables = malloc(sizeof(HashTable*) * ce->num_traits);
+	resulting_table = (HashTable *) malloc(sizeof(HashTable));
+	zend_hash_init_ex(resulting_table, 10, // TODO: revisit this start size, may be its not optimal
+						  //NULL, ZEND_FUNCTION_DTOR, 0, 0);
+					  	  NULL, NULL, 0, 0);
+	
+	for (i = 0; i < ce->num_traits; i++) {
+		function_tables[i] = (HashTable *) malloc(sizeof(HashTable));
+    	zend_hash_init_ex(function_tables[i], ce->traits[i]->function_table.nNumOfElements, 
+						  //NULL, ZEND_FUNCTION_DTOR, 0, 0);
+						  NULL, NULL, 0, 0);
+		// copies functions and applies defined aliasing
+		copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases[i]);
+	}
+	
+	// now merge trait methods
+	for (i = 0; i < ce->num_traits; i++) {
+		zend_hash_apply_with_arguments(function_tables[i], (apply_func_args_t)_merge_functions, 5, //5 is number of args for apply_func
+						i, ce->num_traits, resulting_table, function_tables, ce);
+	}
+	
+	// now the resulting_table contains all trait methods we would have to 
+	// add to the class
+	// in the following step the methods are inserted into the method table
+	// if there is already a method with the same name it is replaced iff ce != fn.scope
+	// --> all inherited methods are overridden, methods defined in the class are leaved
+	// untouched
+	zend_hash_apply_with_arguments(resulting_table, (apply_func_args_t)_merge_functions_to_class, 1, ce TSRMLS_CC);
+	
+	// free temporary function tables
+	for (i = 0; i < ce->num_traits; i++) {
+		//zend_hash_destroy(function_tables[i]); //
+		zend_hash_graceful_destroy(function_tables[i]);
+		free(function_tables[i]);
+	}
+	free(function_tables);
+	
+	// free temporary resulting table
+	//zend_hash_destroy(resulting_table); //
+	zend_hash_graceful_destroy(resulting_table);
+	free(resulting_table);
+
+	// there is still something to do
+	// now we propagte by traits implemented interfaces
+	for (i = 0; i < ce->num_traits; i++) {
+		for (j = 0; j < ce->traits[i]->num_interfaces; j++) {
+			zend_do_implement_interface(ce, ce->traits[i]->interfaces[j] TSRMLS_CC);
+		}
+	}
+
+	zend_verify_abstract_class(ce TSRMLS_CC);
+}
 
 ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time)
 {
@@ -2542,7 +2951,10 @@
 
 			break;
 		case ZEND_ADD_INTERFACE:
+		case ZEND_ADD_TRAIT:
+		case ZEND_BIND_TRAITS:
 			/* We currently don't early-bind classes that implement interfaces */
+			/* Classes with traits are handled exactly the same, no early-bind here */
 			return;
 		default:
 			zend_error(E_COMPILE_ERROR, "Invalid binding type");
@@ -2970,6 +3384,46 @@
 	opline->extended_value = CG(active_class_entry)->num_interfaces++;
 }
 
+// STEFAN ADD
+// TODO: Test this
+void zend_do_implements_trait(znode *trait_znode, znode* aliases TSRMLS_DC)
+{
+	zend_op *opline;
+	
+	switch (trait_znode->u.EA.type) {
+		case ZEND_FETCH_CLASS_SELF:
+			zend_error(E_COMPILE_ERROR, "Cannot use 'self' as trait name as it is reserved");
+			break;
+		case ZEND_FETCH_CLASS_PARENT:
+			zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as trait name as it is reserved");
+			break;
+		default:
+			if (CG(active_op_array)->last > 0) {
+				opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
+				if (opline->opcode == ZEND_FETCH_CLASS) {
+					// set this will avoid early binding, think it is as usefull as
+					// it is for interfaces
+					opline->extended_value = ZEND_FETCH_CLASS_TRAIT;
+				}
+			}
+			break;
+	}
+
+	opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+	opline->opcode = ZEND_ADD_TRAIT;
+	opline->op1 = CG(implementing_class);
+	opline->op2 = *trait_znode;
+	opline->extended_value = aliases->u.var; // TODO: check whether this leads to problems
+}
+
+void zend_do_binds_traits(TSRMLS_D)
+{
+	zend_op *opline;
+
+	opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+	opline->opcode = ZEND_BIND_TRAITS;
+	opline->op1 = CG(implementing_class);
+}
 
 ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length, int internal)
 {
@@ -4235,6 +4689,9 @@
 		ce->parent = NULL;
 		ce->num_interfaces = 0;
 		ce->interfaces = NULL;
+		ce->num_traits = 0;
+		ce->traits = NULL;
+		ce->trait_aliases = NULL;
 		ce->module = NULL;
 		ce->serialize = NULL;
 		ce->unserialize = NULL;
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.13
diff -u -r1.316.2.8.2.13 zend_compile.h
--- Zend/zend_compile.h	31 Dec 2007 07:20:02 -0000	1.316.2.8.2.13
+++ Zend/zend_compile.h	16 Feb 2008 21:03:18 -0000
@@ -115,6 +115,7 @@
 #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS	0x20
 #define ZEND_ACC_FINAL_CLASS	            0x40
 #define ZEND_ACC_INTERFACE		            0x80
+#define ZEND_ACC_TRAIT						0x100
 
 /* op_array flags */
 #define ZEND_ACC_INTERACTIVE				0x10
@@ -421,6 +422,15 @@
 ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC);
 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC);
 void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);
+void zend_do_implements_trait(znode *interface_znode, znode* aliases TSRMLS_DC); //STEFAN ADD
+ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait, zend_trait_alias** aliases TSRMLS_DC);
+ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC);
+void zend_do_binds_traits(TSRMLS_D);
+//ZEND_API void zend_do_add_trait_preparative_to_class(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC);
+
+void init_trait_alias_list(znode* result, znode* trait_alias TSRMLS_DC);
+void add_trait_alias(znode* result, znode* trait_alias TSRMLS_DC);
+void init_trait_alias(znode* result, znode* method_name, znode* alias, znode* modifiers TSRMLS_DC);
 
 ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC);
 void zend_do_early_binding(TSRMLS_D);
@@ -591,6 +601,7 @@
 #define ZEND_FETCH_CLASS_GLOBAL		4
 #define ZEND_FETCH_CLASS_AUTO		5
 #define ZEND_FETCH_CLASS_INTERFACE	6
+#define ZEND_FETCH_CLASS_TRAIT		7
 #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80
 
 /* variable parsing type (compile-time) */
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.331.2.20.2.26
diff -u -r1.331.2.20.2.26 zend_execute_API.c
--- Zend/zend_execute_API.c	15 Feb 2008 07:44:45 -0000	1.331.2.20.2.26
+++ Zend/zend_execute_API.c	16 Feb 2008 21:03:19 -0000
@@ -1506,6 +1506,8 @@
 		if (use_autoload) {
 			if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
 				zend_error(E_ERROR, "Interface '%s' not found", class_name);
+			} else if (fetch_type == ZEND_FETCH_CLASS_TRAIT) {
+				zend_error(E_ERROR, "Trait '%s' not found", class_name);
 			} else {
 				zend_error(E_ERROR, "Class '%s' not found", class_name);
 			}
@@ -1547,7 +1549,9 @@
 {
 	zend_abstract_info ai;
 
-	if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) && !(ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
+	if ((ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) 
+			&& !(ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)
+			&& !(ce->ce_flags & ZEND_ACC_TRAIT)) {
 		memset(&ai, 0, sizeof(ai));
 
 		zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t) zend_verify_abstract_class_function, &ai TSRMLS_CC);
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.160.2.4.2.9
diff -u -r1.160.2.4.2.9 zend_language_parser.y
--- Zend/zend_language_parser.y	28 Dec 2007 13:38:19 -0000	1.160.2.4.2.9
+++ Zend/zend_language_parser.y	16 Feb 2008 21:03:19 -0000
@@ -120,9 +120,11 @@
 %token T_EMPTY
 %token T_HALT_COMPILER
 %token T_CLASS
+%token T_TRAIT
 %token T_INTERFACE
 %token T_EXTENDS
 %token T_IMPLEMENTS
+%token T_USES
 %token T_OBJECT_OPERATOR
 %token T_DOUBLE_ARROW
 %token T_LIST
@@ -286,6 +288,7 @@
 unticked_class_declaration_statement:
 		class_entry_type T_STRING extends_from
 			{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
+			uses_list
 			implements_list
 			'{'
 				class_statement_list
@@ -302,6 +305,7 @@
 class_entry_type:
 		T_CLASS			{ $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; }
 	|	T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
+	|	T_TRAIT { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_TRAIT; }
 	|	T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; }
 ;
 
@@ -329,6 +333,42 @@
 	|	interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
 ;
 
+/* STEFAN ADDED TO SUPPORT TRAITS */
+uses_list:
+		/* empty */
+	|	T_USES trait_list { zend_do_binds_traits(TSRMLS_C); }
+;
+
+trait_list:
+		fully_qualified_class_name trait_aliases { zend_do_implements_trait(&$1, &$2 TSRMLS_CC); }
+	| 	trait_list ',' fully_qualified_class_name trait_aliases { zend_do_implements_trait(&$3, &$4 TSRMLS_CC); }
+;
+
+trait_aliases:
+		/* empty */				{ $$.u.var = 0x0; }
+	|	'(' trait_alias_list ')' { $$ = $2; }
+;
+
+trait_alias_list:
+		/* empty */
+	|	non_empty_trait_alias_list { $$ = $1; }
+;
+
+non_empty_trait_alias_list:
+		trait_alias { init_trait_alias_list(&$$, &$1 TSRMLS_CC); }
+	|	non_empty_trait_alias_list ',' trait_alias { add_trait_alias(&$1, &$3 TSRMLS_CC); $$ = $1; }
+;
+
+trait_alias:
+		trait_modifiers T_STRING T_DOUBLE_ARROW T_STRING { init_trait_alias(&$$, &$4, &$2, &$1 TSRMLS_CC); }
+	|	'!' T_STRING { init_trait_alias(&$$, &$2, NULL, NULL TSRMLS_CC); }
+;
+
+trait_modifiers:
+		/* empty */					{ Z_LVAL($$.u.constant) = 0x0; } /* No change of methods visibility */
+	|	non_empty_member_modifiers	{ $$ = $1; } /* REM: Keep in mind, there are not only visibility modifiers */
+;
+
 foreach_optional_arg:
 		/* empty */						{ $$.op_type = IS_UNUSED; }
 	|	T_DOUBLE_ARROW foreach_variable	{ $$ = $2; }
Index: Zend/zend_language_scanner.l
===================================================================
RCS file: /repository/ZendEngine2/zend_language_scanner.l,v
retrieving revision 1.131.2.11.2.13
diff -u -r1.131.2.11.2.13 zend_language_scanner.l
--- Zend/zend_language_scanner.l	9 Sep 2007 16:33:34 -0000	1.131.2.11.2.13
+++ Zend/zend_language_scanner.l	21 Jan 2008 22:14:35 -0000
@@ -1097,6 +1097,10 @@
 	return T_CLASS;
 }
 
+<ST_IN_SCRIPTING>"trait" {
+	return T_TRAIT;
+}
+
 <ST_IN_SCRIPTING>"interface" {
 	return T_INTERFACE;
 }
@@ -1109,6 +1113,10 @@
 	return T_IMPLEMENTS;
 }
 
+<ST_IN_SCRIPTING>"uses" {
+	return T_USES;
+}
+
 <ST_IN_SCRIPTING>"->" {
 	yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
 	return T_OBJECT_OPERATOR;
Index: Zend/zend_opcode.c
===================================================================
RCS file: /repository/ZendEngine2/zend_opcode.c,v
retrieving revision 1.110.2.6.2.5
diff -u -r1.110.2.6.2.5 zend_opcode.c
--- Zend/zend_opcode.c	31 Dec 2007 07:20:03 -0000	1.110.2.6.2.5
+++ Zend/zend_opcode.c	16 Feb 2008 21:03:20 -0000
@@ -188,9 +188,32 @@
 			if (ce->num_interfaces > 0 && ce->interfaces) {
 				efree(ce->interfaces);
 			}
+			if (ce->num_traits > 0 && ce->traits) {
+				efree(ce->traits);
+			}
 			if (ce->doc_comment) {
 				efree(ce->doc_comment);
 			}
+		
+		    if (ce->trait_aliases) {
+				size_t i;
+				for (i = 0; i < ce->num_traits; i++) {
+					size_t j = 0;
+					if (ce->trait_aliases[i]) {
+						while (ce->trait_aliases[i][j]) {
+							efree(ce->trait_aliases[i][j]->method_name);
+							if (ce->trait_aliases[i][j]->alias) {
+								efree(ce->trait_aliases[i][j]->alias); // is just NULL if method was marked to be excluded
+							}
+							efree(ce->trait_aliases[i][j]);
+							j++;
+						}
+						efree(ce->trait_aliases[i]);
+					}
+					
+				}
+				efree(ce->trait_aliases);
+			}
 			efree(ce);
 			break;
 		case ZEND_INTERNAL_CLASS:
@@ -203,6 +226,10 @@
 			if (ce->num_interfaces > 0) {
 				free(ce->interfaces);
 			}
+			//TODO: internal class have to be handled somehow?!
+			//if (ce->num_traits > 0) {
+			//	free(ce->traits);
+			//}
 			if (ce->doc_comment) {
 				free(ce->doc_comment);
 			}
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.59.2.29.2.54
diff -u -r1.59.2.29.2.54 zend_vm_def.h
--- Zend/zend_vm_def.h	31 Dec 2007 07:20:03 -0000	1.59.2.29.2.54
+++ Zend/zend_vm_def.h	16 Feb 2008 21:03:22 -0000
@@ -2514,11 +2514,13 @@
 	zval *object_zval;
 	zend_function *constructor;
 
-	if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
+	if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_TRAIT)) {
 		char *class_type;
 
 		if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) {
 			class_type = "interface";
+		} else if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_TRAIT) {
+			class_type = "trait";
 		} else {
 			class_type = "abstract class";
 		}
@@ -3784,6 +3786,31 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(151, ZEND_ADD_TRAIT, ANY, ANY)
+{
+	zend_op *opline = EX(opline);
+	zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry;
+	zend_class_entry *trait = EX_T(opline->op2.u.var).class_entry;
+
+	if (!(trait->ce_flags & ZEND_ACC_TRAIT)) {
+		zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not a trait", ce->name, trait->name);
+	}
+
+	zend_do_implement_trait(ce, trait TSRMLS_CC);
+
+	ZEND_VM_NEXT_OPCODE();
+}
+
+ZEND_VM_HANDLER(152, ZEND_BIND_TRAITS, ANY, ANY)
+{
+	zend_op *opline = EX(opline);
+	zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry;
+	
+	zend_do_bind_traits(ce TSRMLS_CC);
+	
+	ZEND_VM_NEXT_OPCODE();
+}
+
 ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
 {
 	zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
Index: Zend/zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.62.2.30.2.55
diff -u -r1.62.2.30.2.55 zend_vm_execute.h
--- Zend/zend_vm_execute.h	31 Dec 2007 07:20:03 -0000	1.62.2.30.2.55
+++ Zend/zend_vm_execute.h	16 Feb 2008 21:03:33 -0000
@@ -392,11 +392,13 @@
 	zval *object_zval;
 	zend_function *constructor;
 
-	if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
+	if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_TRAIT)) {
 		char *class_type;
 
 		if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) {
 			class_type = "interface";
+		} else if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_TRAIT) {
+			class_type = "trait";
 		} else {
 			class_type = "abstract class";
 		}
@@ -524,6 +526,32 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_ADD_TRAIT_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry;
+	zend_class_entry *trait = EX_T(opline->op2.u.var).class_entry;
+	zend_trait_alias** aliases = opline->extended_value;
+
+	if (!(trait->ce_flags & ZEND_ACC_TRAIT)) {
+		zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not a trait", ce->name, trait->name);
+	}
+
+	zend_do_implement_trait(ce, trait, aliases TSRMLS_CC);
+
+	ZEND_VM_NEXT_OPCODE();
+}
+
+static int ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	zend_op *opline = EX(opline);
+	zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry;
+
+	zend_do_bind_traits(ce TSRMLS_CC);
+
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
@@ -30727,6 +30755,56 @@
   	ZEND_USER_OPCODE_SPEC_HANDLER,
   	ZEND_USER_OPCODE_SPEC_HANDLER,
   	ZEND_USER_OPCODE_SPEC_HANDLER,
+  	ZEND_ADD_TRAIT_SPEC_HANDLER, // STEFAN added vor opcode 151 and 152
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_ADD_TRAIT_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
+	ZEND_BIND_TRAITS_SPEC_HANDLER,
   	ZEND_NULL_HANDLER
   };
   zend_opcode_handlers = (opcode_handler_t*)labels;
Index: Zend/zend_vm_opcodes.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_opcodes.h,v
retrieving revision 1.42.2.17.2.2
diff -u -r1.42.2.17.2.2 zend_vm_opcodes.h
--- Zend/zend_vm_opcodes.h	31 Dec 2007 07:20:04 -0000	1.42.2.17.2.2
+++ Zend/zend_vm_opcodes.h	16 Feb 2008 21:03:33 -0000
@@ -147,3 +147,5 @@
 #define ZEND_ISSET_ISEMPTY_PROP_OBJ  148
 #define ZEND_HANDLE_EXCEPTION        149
 #define ZEND_USER_OPCODE             150
+#define ZEND_ADD_TRAIT				 151
+#define ZEND_BIND_TRAITS		 	 152