Index: Zend/zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.293.2.11.2.9.2.16
diff -u -r1.293.2.11.2.9.2.16 zend.h
--- Zend/zend.h	22 Jan 2008 09:27:46 -0000	1.293.2.11.2.9.2.16
+++ Zend/zend.h	21 Feb 2008 15:47:29 -0000
@@ -394,6 +394,31 @@
 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;
@@ -439,6 +464,10 @@
 	zend_class_entry **interfaces;
 	zend_uint num_interfaces;
 
+	zend_class_entry **traits;
+	zend_uint num_traits;
+	zend_trait_alias*** trait_aliases;
+
 	char *filename;
 	zend_uint line_start;
 	zend_uint line_end;
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.647.2.27.2.41.2.43
diff -u -r1.647.2.27.2.41.2.43 zend_compile.c
--- Zend/zend_compile.c	20 Feb 2008 12:05:56 -0000	1.647.2.27.2.41.2.43
+++ Zend/zend_compile.c	21 Feb 2008 18:09:48 -0000
@@ -2649,7 +2649,10 @@
 		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);
@@ -2834,7 +2837,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");
@@ -4716,6 +4722,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;
@@ -4952,6 +4961,461 @@
 }
 /* }}} */
 
+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;
+}
+
+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 or interface
+		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);
+	// now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed
+	if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
+		ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
+	}
+}
+
+void zend_do_implements_trait(znode *trait_name, znode* aliases TSRMLS_DC)
+{
+	zend_op *opline;
+	znode trait_node;
+
+	zend_do_fetch_class(&trait_node, trait_name TSRMLS_CC);
+	switch (trait_node.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_node;
+	if (aliases) {
+		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_dirname
    Returns directory name component of path */
 ZEND_API size_t zend_dirname(char *path, size_t len)
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.316.2.8.2.12.2.14
diff -u -r1.316.2.8.2.12.2.14 zend_compile.h
--- Zend/zend_compile.h	12 Feb 2008 00:20:33 -0000	1.316.2.8.2.12.2.14
+++ Zend/zend_compile.h	21 Feb 2008 19:51:59 -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
@@ -422,6 +423,14 @@
 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);
+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);
 
@@ -602,6 +611,7 @@
 #define ZEND_FETCH_CLASS_AUTO		5
 #define ZEND_FETCH_CLASS_INTERFACE	6
 #define ZEND_FETCH_CLASS_STATIC		7
+#define ZEND_FETCH_CLASS_TRAIT		9
 #define ZEND_FETCH_CLASS_MASK        0x0f
 #define ZEND_FETCH_CLASS_RT_NS_CHECK 0x20
 #define ZEND_FETCH_CLASS_RT_NS_NAME  0x40
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.331.2.20.2.24.2.25
diff -u -r1.331.2.20.2.24.2.25 zend_execute_API.c
--- Zend/zend_execute_API.c	2 Feb 2008 15:48:04 -0000	1.331.2.20.2.24.2.25
+++ Zend/zend_execute_API.c	21 Feb 2008 15:54:28 -0000
@@ -1641,6 +1641,8 @@
 			if (!silent) {
 				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);
 				}
@@ -1691,7 +1693,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.8.2.17
diff -u -r1.160.2.4.2.8.2.17 zend_language_parser.y
--- Zend/zend_language_parser.y	12 Feb 2008 09:27:45 -0000	1.160.2.4.2.8.2.17
+++ Zend/zend_language_parser.y	21 Feb 2008 16:24:18 -0000
@@ -121,6 +121,7 @@
 %token T_HALT_COMPILER
 %token T_CLASS
 %token T_INTERFACE
+%token T_TRAIT
 %token T_EXTENDS
 %token T_IMPLEMENTS
 %token T_OBJECT_OPERATOR
@@ -301,7 +302,7 @@
 			implements_list
 			'{'
 				class_statement_list
-			'}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
+			'}' { zend_do_binds_traits(TSRMLS_C); zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
 	|	interface_entry T_STRING
 			{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
 			interface_extends_list
@@ -314,6 +315,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; }
 ;
 
@@ -499,10 +501,36 @@
 class_statement:
 		variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';'
 	|	class_constant_declaration ';'
+	|	trait_use_statement
 	|	method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, &$1 TSRMLS_CC); } '('
 			parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
 ;
 
+trait_use_statement:
+		T_USE fully_qualified_class_name ';' { zend_do_implements_trait(&$2, NULL TSRMLS_CC); }
+	|	T_USE fully_qualified_class_name '{' trait_alias_list '}' { zend_do_implements_trait(&$2, &$4 TSRMLS_CC); }
+;
+
+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); }
+	|	trait_modifiers T_STRING { init_trait_alias(&$$, &$2, &$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 */
+;
 
 method_body:
 		';' /* abstract method */		{ Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
Index: Zend/zend_language_scanner.l
===================================================================
RCS file: /repository/ZendEngine2/zend_language_scanner.l,v
retrieving revision 1.131.2.11.2.13.2.6
diff -u -r1.131.2.11.2.13.2.6 zend_language_scanner.l
--- Zend/zend_language_scanner.l	12 Feb 2008 09:27:45 -0000	1.131.2.11.2.13.2.6
+++ Zend/zend_language_scanner.l	21 Feb 2008 16:21:17 -0000
@@ -1106,6 +1106,10 @@
 	return T_INTERFACE;
 }
 
+<ST_IN_SCRIPTING>"trait" {
+	return T_TRAIT;
+}
+
 <ST_IN_SCRIPTING>"extends" {
 	return T_EXTENDS;
 }
Index: Zend/zend_opcode.c
===================================================================
RCS file: /repository/ZendEngine2/zend_opcode.c,v
retrieving revision 1.110.2.6.2.3.2.5
diff -u -r1.110.2.6.2.3.2.5 zend_opcode.c
--- Zend/zend_opcode.c	31 Dec 2007 07:17:04 -0000	1.110.2.6.2.3.2.5
+++ Zend/zend_opcode.c	21 Feb 2008 15:56:36 -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:
@@ -206,6 +229,7 @@
 			if (ce->doc_comment) {
 				free(ce->doc_comment);
 			}
+			//TODO: internal class need to free trait resources, too.
 			free(ce);
 			break;
 	}
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.59.2.29.2.48.2.37
diff -u -r1.59.2.29.2.48.2.37 zend_vm_def.h
--- Zend/zend_vm_def.h	20 Feb 2008 12:05:56 -0000	1.59.2.29.2.48.2.37
+++ Zend/zend_vm_def.h	21 Feb 2008 16:07:34 -0000
@@ -2693,11 +2693,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";
 		}
@@ -4009,6 +4011,32 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(153, 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;
+	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();
+}
+
+ZEND_VM_HANDLER(154, 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.49.2.36
diff -u -r1.62.2.30.2.49.2.36 zend_vm_execute.h
--- Zend/zend_vm_execute.h	20 Feb 2008 12:05:56 -0000	1.62.2.30.2.49.2.36
+++ Zend/zend_vm_execute.h	21 Feb 2008 16:07:36 -0000
@@ -513,6 +513,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;
@@ -33029,6 +33055,56 @@
   	ZEND_JMP_SET_SPEC_CV_HANDLER,
   	ZEND_JMP_SET_SPEC_CV_HANDLER,
   	ZEND_JMP_SET_SPEC_CV_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_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.1.2.4
diff -u -r1.42.2.17.2.1.2.4 zend_vm_opcodes.h
--- Zend/zend_vm_opcodes.h	31 Dec 2007 07:17:06 -0000	1.42.2.17.2.1.2.4
+++ Zend/zend_vm_opcodes.h	21 Feb 2008 16:01:43 -0000
@@ -150,3 +150,5 @@
 #define ZEND_HANDLE_EXCEPTION        149
 #define ZEND_USER_OPCODE             150
 #define ZEND_JMP_SET                 152
+#define ZEND_ADD_TRAIT				 153
+#define ZEND_BIND_TRAITS		 	 154
\ No newline at end of file
