? b
? fileGetContentsVar7.dir
? run-tests.sh
? traits.patch
? Zend/.DS_Store
? Zend/tests/.DS_Store
? Zend/tests/traits
Index: Zend/zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.364
diff -u -r1.364 zend.h
--- Zend/zend.h	31 Dec 2008 11:12:28 -0000	1.364
+++ Zend/zend.h	18 Jan 2009 13:48:34 -0000
@@ -22,7 +22,7 @@
 #ifndef ZEND_H
 #define ZEND_H
 
-#define ZEND_VERSION "3.0.0-dev"
+#define ZEND_VERSION "3.0.0-dev-with-traits"
 
 #define ZEND_ENGINE_2
 
@@ -449,6 +449,44 @@
 typedef struct _zend_serialize_data zend_serialize_data;
 typedef struct _zend_unserialize_data zend_unserialize_data;
 
+struct _zend_trait_method_reference {
+	zstr method_name;
+	unsigned int mname_len;
+	
+	zend_class_entry *ce;
+	
+	zstr class_name;
+	unsigned int cname_len;
+};
+typedef struct _zend_trait_method_reference	zend_trait_method_reference;
+
+struct _zend_trait_precedence {
+	zend_trait_method_reference *trait_method;
+	
+	zend_class_entry** exclude_from_classes;
+	
+	union _zend_function* function;
+};
+typedef struct _zend_trait_precedence zend_trait_precedence;
+
+struct _zend_trait_alias {
+	zend_trait_method_reference *trait_method;
+	
+	/**
+	* name for method to be added
+	*/
+	zstr alias;
+	unsigned int alias_len;
+	
+	/**
+	* 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;
 	zstr name;
@@ -493,6 +531,11 @@
 
 	zend_class_entry **interfaces;
 	zend_uint num_interfaces;
+	
+	zend_class_entry **traits;
+	zend_uint num_traits;
+	zend_trait_alias **trait_aliases;
+	zend_trait_precedence **trait_precedences;
 
 	char *filename;
 	zend_uint line_start;
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.848
diff -u -r1.848 zend_compile.c
--- Zend/zend_compile.c	14 Jan 2009 13:57:59 -0000	1.848
+++ Zend/zend_compile.c	18 Jan 2009 13:48:35 -0000
@@ -2988,7 +2988,7 @@
 
 	if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
 		ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
-	} else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES)) {
+	} else if (!(ce->ce_flags & ZEND_ACC_IMPLEMENT_INTERFACES) && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) {
 		/* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
 		zend_verify_abstract_class(ce TSRMLS_CC);
 	}
@@ -3046,6 +3046,497 @@
 }
 /* }}} */
 
+ZEND_API void zend_do_implement_trait(zend_class_entry *ce, const zend_class_entry *trait TSRMLS_DC) /* {{{ */
+{
+	zend_uint i, ignore = 0;
+	zend_uint current_trait_num = ce->num_traits;
+	zend_uint parent_trait_num  = ce->parent ? ce->parent->num_traits : 0;
+	
+	for (i = 0; i < ce->num_traits; i++) {
+		if (ce->traits[i] == NULL) {
+			memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
+			i--;
+		} else if (ce->traits[i] == trait) {
+			if (i < parent_trait_num) {
+				ignore = 1;
+			}
+		}
+	}
+	if (!ignore) {
+		if (ce->num_traits >= current_trait_num) {
+			if (ce->type == ZEND_INTERNAL_CLASS) {
+				ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
+			} else {
+				ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
+			}
+		}
+		ce->traits[ce->num_traits++] = trait;
+	}
+}
+/* }}} */
+
+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;
+	//zstr lcname;
+	size_t collision = 0;
+	size_t abstract_solved = 0;
+	//unsigned int 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*);
+	
+	for (i = 0; i < count; i++) {
+		if (i == current) {
+			continue; // just skip this, cause its the table this function is applied on
+		}
+		
+		if (zend_u_hash_find(function_tables[i], UG(unicode)?IS_UNICODE:IS_STRING, hash_key->arKey, hash_key->nKeyLength, &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_u_hash_del(function_tables[i], UG(unicode)?IS_UNICODE:IS_STRING, hash_key->arKey, hash_key->nKeyLength);
+			} 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_u_hash_del(function_tables[i], UG(unicode)?IS_UNICODE:IS_STRING, hash_key->arKey, hash_key->nKeyLength);
+				}
+			}
+		}
+	}
+	
+	if (collision) {
+		zend_function* class_fn;
+		// make sure method is not already overridden in class
+		
+		if (zend_u_hash_find(&ce->function_table, UG(unicode)?IS_UNICODE:IS_STRING, hash_key->arKey, hash_key->nKeyLength, &class_fn) == FAILURE
+			|| class_fn->common.scope != ce) {
+				zend_error(E_WARNING, "Trait method %v has not been applied, because there are collisions with other trait methods on %v", 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_u_hash_add(resulting_table, ZEND_STR_TYPE, hash_key->arKey, hash_key->nKeyLength, fn, sizeof(zend_function), NULL)==FAILURE) {
+			zend_error(E_ERROR, "Trait method %v has not been applied, because failure occured during updating resulting trait method table.", fn->common.function_name);
+		}
+	}
+	
+	//efree(lcname.v);
+	return ZEND_HASH_APPLY_REMOVE;
+}
+/* }}} */
+
+#define IS_EQUAL(mname, mname_len, str) \
+		mname_len == sizeof(str)-1 && ZEND_U_EQUAL(UG(unicode)?IS_UNICODE:IS_STRING, mname, mname_len, str, sizeof(str)-1)
+
+#define _ADD_MAGIC_METHOD(ce, mname, mname_len, fe) { \
+	if (IS_EQUAL(mname, mname_len, "__clone")) 	{	(ce)->clone			= (fe); (fe)->common.fn_flags = ZEND_ACC_CLONE; } \
+	else if (IS_EQUAL(mname, mname_len, "__get"))		(ce)->__get			= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__set"))		(ce)->__set			= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__call"))		(ce)->__call		= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__unset"))		(ce)->__unset		= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__isset"))		(ce)->__isset		= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__callstatic"))(ce)->__callstatic	= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "__tostring"))	(ce)->__tostring	= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "serialize_func"))	(ce)->serialize_func	= (fe); \
+	else if (IS_EQUAL(mname, mname_len, "unserialize_func"))(ce)->unserialize_func	= (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, zstr newname)
+{
+	zend_compiled_variable *dupvars;
+	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 = ezstrndup(UG(unicode)?IS_UNICODE:IS_STRING, fe->op_array.vars[i].name, fe->op_array.vars[i].name_len);
+		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;
+	fe->op_array.function_name = newname;
+
+	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 = ezstrndup(UG(unicode)?IS_UNICODE:IS_STRING, tmpArginfo[i].name, tmpArginfo[i].name_len);
+			if (tmpArginfo[i].class_name.v) {
+				tmpArginfo[i].class_name = ezstrndup(UG(unicode)?IS_UNICODE:IS_STRING, tmpArginfo[i].class_name, tmpArginfo[i].class_name_len);
+			}
+		}
+		fe->op_array.arg_info = tmpArginfo;
+	}
+
+	fe->op_array.doc_comment = ezstrndup(UG(unicode)?IS_UNICODE:IS_STRING, 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*);
+	int add = 0;	
+	zend_function* existing_fn;
+	
+	if (zend_u_hash_find(&ce->function_table, ZEND_STR_TYPE, hash_key->arKey, hash_key->nKeyLength, (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_u_hash_del(&ce->function_table, ZEND_STR_TYPE, hash_key->arKey, hash_key->nKeyLength);
+	} 
+	
+	if (add) {
+		fn->common.scope = ce;
+		
+		// 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_u_hash_add(&ce->function_table, UG(unicode)?IS_UNICODE:IS_STRING, hash_key->arKey, hash_key->nKeyLength, 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);
+		}
+		
+		_ADD_MAGIC_METHOD(ce, hash_key->arKey, hash_key->nKeyLength, 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.v);
+	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;
+	HashTable* exclude_table;
+	zstr lcname;
+	unsigned int lcname_len;
+	unsigned int fnname_len;
+	zend_function fn_copy;
+	
+	size_t i = 0;
+	target = va_arg(args, HashTable*);
+	aliases = va_arg(args, zend_trait_alias**);
+	exclude_table = va_arg(args, HashTable*);
+	
+	fnname_len = USTR_LEN(fn->common.function_name);
+
+	// apply aliases which are qualified with a class name, there should not be any ambiguatty 
+	if (aliases) {
+		while (aliases[i]) {
+			if (fn->common.scope == aliases[i]->trait_method->ce &&
+				((UG(unicode) && zend_u_binary_strcasecmp(aliases[i]->trait_method->method_name.u, aliases[i]->trait_method->mname_len, fn->common.function_name.u, fnname_len) == 0)
+				|| zend_binary_strcasecmp(aliases[i]->trait_method->method_name.s, aliases[i]->trait_method->mname_len, fn->common.function_name.s, fnname_len) == 0)) {
+				if (aliases[i]->alias.v) {
+					fn_copy = *fn;
+					php_runkit_function_copy_ctor(&fn_copy, ezstrndup(ZEND_STR_TYPE, aliases[i]->alias, aliases[i]->alias_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_len = 0;
+					lcname = zend_u_str_case_fold(ZEND_STR_TYPE, aliases[i]->alias, aliases[i]->alias_len, 1, &lcname_len);
+
+					if (zend_u_hash_add(target, ZEND_STR_TYPE, lcname, lcname_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
+						zend_error(E_ERROR, "Failed to added aliased trait method (%v) 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.v);
+				}
+			}
+			i++;
+		}
+	}
+
+	lcname_len = 0;
+	lcname = zend_u_str_case_fold(ZEND_STR_TYPE, fn->common.function_name, fnname_len, 1, &lcname_len);
+	void* dummy;
+	if (zend_u_hash_find(exclude_table, ZEND_STR_TYPE, lcname, lcname_len, &dummy) == FAILURE) {
+		// is not in hashtable, thus, function is not to be excluded
+		fn_copy = *fn;
+		php_runkit_function_copy_ctor(&fn_copy, ezstrndup(ZEND_STR_TYPE, fn->common.function_name, fnname_len));
+		
+		// apply aliases which are not qualified by a class name, or which have not alias name, just setting visibility
+		// TODO: i am still not sure, that there will be no ambigousities...
+		
+		if (aliases) {
+			i = 0;
+			while (aliases[i]) {
+				if ((!aliases[i]->trait_method->ce || fn->common.scope == aliases[i]->trait_method->ce) &&
+					((UG(unicode) && zend_u_binary_strcasecmp(aliases[i]->trait_method->method_name.u, aliases[i]->trait_method->mname_len, fn->common.function_name.u, fnname_len) == 0)
+					 || zend_binary_strcasecmp(aliases[i]->trait_method->method_name.s, aliases[i]->trait_method->mname_len, fn->common.function_name.s, fnname_len) == 0)) {
+					if (aliases[i]->alias.v) {
+						zend_function fn_copy2 = *fn;
+						php_runkit_function_copy_ctor(&fn_copy2, ezstrndup(ZEND_STR_TYPE, aliases[i]->alias, aliases[i]->alias_len));
+						
+						if (aliases[i]->modifiers) { // if it is 0, no modifieres has been changed
+							fn_copy2.common.fn_flags = aliases[i]->modifiers;
+							if (!(aliases[i]->modifiers & ZEND_ACC_PPP_MASK)) {
+								fn_copy2.common.fn_flags |= ZEND_ACC_PUBLIC;
+							}
+						}
+						
+						unsigned int lcname2_len = 0;
+						zstr lcname2 = zend_u_str_case_fold(ZEND_STR_TYPE, aliases[i]->alias, aliases[i]->alias_len, 1, &lcname2_len);
+						
+						if (zend_u_hash_add(target, ZEND_STR_TYPE, lcname2, lcname2_len+1, &fn_copy2, sizeof(zend_function), NULL)==FAILURE) {
+							zend_error(E_ERROR, "Failed to added aliased trait method (%v) to trait table. Propably there is already a trait method with same name\n", fn_copy2.common.function_name);
+						}
+						efree(lcname2.v);
+					} else {
+						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;
+							}
+						}
+					}
+				}
+				i++;
+			}
+		}
+		
+		
+		if (zend_u_hash_add(target, ZEND_STR_TYPE, lcname, lcname_len+1, &fn_copy, sizeof(zend_function), NULL)==FAILURE) {
+			zend_error(E_ERROR, "Failed to added trait method (%v) to trait table. Propably there is already a trait method with same name\n", fn_copy.common.function_name);
+		}
+	}
+	
+	efree(lcname.v);
+
+	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, HashTable* exclude_table) {
+	zend_hash_apply_with_arguments(source, (apply_func_args_t)_copy_functions, 3, //3 is number of args for apply_func
+			target, aliases, exclude_table);
+}
+
+void init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+	size_t i, j = 0;
+	zend_trait_precedence *cur_precedence;
+	zend_trait_method_reference *cur_method_ref;
+	zend_class_entry *cur_ce;
+	
+	// resolve class references
+	
+	if (ce->trait_precedences) {
+		i = 0;
+		while ((cur_precedence = ce->trait_precedences[i])) {
+			cur_ce = zend_u_fetch_class(ZEND_STR_TYPE, cur_precedence->trait_method->class_name, cur_precedence->trait_method->cname_len, ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);
+			cur_precedence->trait_method->ce = cur_ce;
+			
+			if (cur_precedence->exclude_from_classes) {
+				j = 0;
+				while (cur_precedence->exclude_from_classes[j]) {
+					zstr class_name = ZSTR(cur_precedence->exclude_from_classes[j]);
+					cur_ce = zend_u_fetch_class(ZEND_STR_TYPE, class_name, USTR_LEN(class_name), ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);
+					efree(class_name.v);
+					cur_precedence->exclude_from_classes[j] = cur_ce;
+					j++;
+				}
+			}
+			i++;
+		}
+	}
+	
+	if (ce->trait_aliases) {
+		i = 0;
+		while (ce->trait_aliases[i]) {
+			cur_method_ref = ce->trait_aliases[i]->trait_method;
+			if (cur_method_ref->class_name.v) {
+				cur_method_ref->ce = zend_u_fetch_class(ZEND_STR_TYPE, cur_method_ref->class_name, cur_method_ref->cname_len, ZEND_FETCH_CLASS_TRAIT TSRMLS_CC);
+			}
+			i++;
+		}
+	}
+}
+/* }}} */
+
+void compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) {
+	size_t i, j;
+	if (precedences) {
+		i = 0;
+		while (precedences[i]) {
+			if (precedences[i]->exclude_from_classes) {
+				j = 0;
+				while (precedences[i]->exclude_from_classes[j]) {
+					if (precedences[i]->exclude_from_classes[j] == trait) {
+						unsigned int lcname_len;
+						zstr lcname = zend_u_str_case_fold(ZEND_STR_TYPE, precedences[i]->trait_method->method_name, precedences[i]->trait_method->mname_len, 1, &lcname_len);
+						if (zend_u_hash_add(exclude_table, ZEND_STR_TYPE, lcname, lcname_len, NULL, 0, NULL)==FAILURE) {
+							zend_error(E_ERROR, "Failed to evaluate a trait precedence (%v). Method of trait %v was defined to be excluded multiple times.\n", precedences[i]->trait_method->method_name, trait->name);
+						}
+						efree(lcname.v);
+					}
+					j++;
+				}
+			}
+			i++;
+		}
+	}
+}
+
+ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+	HashTable** function_tables;
+	HashTable* resulting_table;
+	HashTable exclude_table;
+	size_t i;
+	
+	if (ce->num_traits <= 0) { return; }
+	
+//	zend_error(E_NOTICE, "Do bind Traits on %v with %d traits.\n Class has already %d methods.\n",
+//			   ce->name.s, ce->num_traits, ce->function_table.nNumOfElements);
+	
+	// complete initialization of trait strutures in ce
+	init_trait_structures(ce);
+	
+	// prepare copies of trait function tables for combination
+	function_tables = malloc(sizeof(HashTable*) * ce->num_traits);
+	resulting_table = (HashTable *) malloc(sizeof(HashTable));
+	zend_u_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, UG(unicode), 0);
+	
+	for (i = 0; i < ce->num_traits; i++) {
+		function_tables[i] = (HashTable *) malloc(sizeof(HashTable));
+    	zend_u_hash_init_ex(function_tables[i], ce->traits[i]->function_table.nNumOfElements, 
+						  //NULL, ZEND_FUNCTION_DTOR, 0, 0);
+						  NULL, NULL, 0, UG(unicode), 0);
+		
+		zend_u_hash_init_ex(&exclude_table, 2, // TODO: revisit this start size, may be its not optimal 
+							NULL, NULL, 0, UG(unicode), 0);
+		compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
+		
+		// copies functions, applies defined aliasing, and excludes unused trait methods
+		copy_trait_function_table(function_tables[i], &ce->traits[i]->function_table, ce->trait_aliases, &exclude_table);
+		zend_hash_graceful_destroy(&exclude_table);
+	}
+	
+	// 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);
+
+	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;
+	}
+}
+/* }}} */
+
+
 ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */
 {
 	zend_function *function;
@@ -3082,6 +3573,93 @@
 }
 /* }}} */
 
+void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC) /* {{{ */
+{
+	zend_class_entry *ce = CG(active_class_entry);
+	zend_add_to_list(&ce->trait_precedences, (void*)precedence_znode->u.var);
+}
+/* }}} */
+
+void zend_add_trait_alias(znode *alias_znode TSRMLS_DC) /* {{{ */
+{
+	zend_class_entry *ce = CG(active_class_entry);
+	zend_add_to_list(&ce->trait_aliases, (void*)alias_znode->u.var);
+}
+/* }}} */
+
+void zend_prepare_reference(znode *result, znode *class_name, znode *method_name TSRMLS_DC) /* {{{ */
+{
+	zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
+	method_ref->ce = NULL;
+	
+	// TODO: check whether this strings have to be copied, but think this is used for class names, too, so should be save somehow
+	if (class_name) {
+		method_ref->class_name = Z_UNIVAL(class_name->u.constant);
+		method_ref->cname_len = Z_UNILEN(class_name->u.constant);
+	} else {
+		method_ref->class_name.v = NULL;
+		method_ref->cname_len = 0;
+	}
+	
+	method_ref->method_name = Z_UNIVAL(method_name->u.constant);
+	method_ref->mname_len = Z_UNILEN(method_name->u.constant);
+	
+	result->u.var = (intptr_t)method_ref;
+}
+/* }}} */
+
+
+void zend_prepare_trait_alias(znode *result, znode *method_reference, znode *modifiers, znode *alias TSRMLS_DC) /* {{{ */
+{
+	zend_trait_alias *trait_alias = emalloc(sizeof(zend_trait_alias));
+	
+	trait_alias->trait_method = (zend_trait_method_reference*)method_reference->u.var;
+	trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
+	
+	if (alias) {
+		trait_alias->alias = Z_UNIVAL(alias->u.constant);
+		trait_alias->alias_len = Z_UNILEN(alias->u.constant);
+	} else {
+		trait_alias->alias.v = NULL;
+	}
+	trait_alias->function = NULL;
+	
+	result->u.var = (intptr_t)trait_alias;
+}
+/* }}} */
+
+//void init_trait_alias(znode* result, const znode* method_name, const znode* alias, const znode* modifiers TSRMLS_DC) /* {{{ */
+/*{
+	zend_trait_alias* trait_alias = emalloc(sizeof(zend_trait_alias));
+	trait_alias->method_name = Z_UNIVAL(method_name->u.constant);
+	
+	// may be method is only excluded, then the alias node is NULL
+	if (alias) {
+		trait_alias->alias = Z_UNIVAL(alias->u.constant);
+		trait_alias->modifiers = Z_LVAL(modifiers->u.constant);
+	} else {
+
+	}
+	trait_alias->function = NULL;
+	
+	
+	result->u.var = trait_alias;
+}
+/* }}} */
+
+void zend_prepare_trait_precedence(znode *result, znode *method_reference, znode *trait_list TSRMLS_DC) /* {{{ */
+{
+	zend_trait_precedence *trait_precedence = emalloc(sizeof(zend_trait_precedence));
+	
+	trait_precedence->trait_method = (zend_trait_method_reference*)method_reference->u.var;
+	trait_precedence->exclude_from_classes = (zend_class_entry**) trait_list->u.var;
+	
+	trait_precedence->function = NULL;
+	
+	result->u.var = (intptr_t)trait_precedence;
+}
+/* }}} */
+
 ZEND_API zend_class_entry *do_bind_class(const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
 {
 	zend_class_entry *ce, **pce;
@@ -3213,7 +3791,10 @@
 			}
 		case ZEND_VERIFY_ABSTRACT_CLASS:
 		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");
@@ -3627,7 +4208,7 @@
 void zend_do_end_class_declaration(const znode *class_token, const znode *parent_token TSRMLS_DC) /* {{{ */
 {
 	zend_class_entry *ce = CG(active_class_entry);
-
+	
 	do_inherit_parent_constructor(ce TSRMLS_CC);
 
 	if (ce->constructor) {
@@ -3667,6 +4248,22 @@
 		ce->num_interfaces = 0;
 		ce->ce_flags |= ZEND_ACC_IMPLEMENT_INTERFACES;
 	}
+	
+	/* Check for traits and proceed like with interfaces.
+	 * The only difference will be a combined handling of them in the end. 
+	 * Thus, we need another opcode here. */
+	if (ce->num_traits > 0) {
+		ce->traits = NULL;
+		ce->num_traits = 0;
+		ce->ce_flags |= ZEND_ACC_IMPLEMENT_TRAITS;
+
+		// opcode generation:
+		zend_op *opline;
+		opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+		opline->opcode = ZEND_BIND_TRAITS;
+		opline->op1 = CG(implementing_class);
+	}
+	
 	CG(active_class_entry) = NULL;
 }
 /* }}} */
@@ -3674,6 +4271,11 @@
 void zend_do_implements_interface(znode *interface_name TSRMLS_DC) /* {{{ */
 {
 	zend_op *opline;
+	
+	// Traits can not implement interfaces
+	if ((CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
+		zend_error(E_COMPILE_ERROR, "Cannot use '%R' as interface on '%R' since it is a Trait", Z_TYPE(interface_name->u.constant), Z_UNIVAL(interface_name->u.constant), ZEND_STR_TYPE, CG(active_class_entry)->name);
+	}
 
 	switch (zend_get_class_fetch_type(Z_TYPE(interface_name->u.constant), Z_UNIVAL(interface_name->u.constant), Z_UNILEN(interface_name->u.constant))) {
 		case ZEND_FETCH_CLASS_SELF:
@@ -3695,6 +4297,30 @@
 }
 /* }}} */
 
+void zend_do_implements_trait(znode *trait_name TSRMLS_DC) /* {{{ */
+{
+	zend_op *opline;
+	
+	switch (zend_get_class_fetch_type(Z_TYPE(trait_name->u.constant), Z_UNIVAL(trait_name->u.constant), Z_UNILEN(trait_name->u.constant))) {
+		case ZEND_FETCH_CLASS_SELF:
+		case ZEND_FETCH_CLASS_PARENT:
+		case ZEND_FETCH_CLASS_STATIC:
+			zend_error(E_COMPILE_ERROR, "Cannot use '%R' as trait name as it is reserved", Z_TYPE(trait_name->u.constant), Z_UNIVAL(trait_name->u.constant));
+			break;
+		default:
+			break;
+	}
+	
+	opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+	opline->opcode = ZEND_ADD_TRAIT;
+	opline->op1 = CG(implementing_class);
+	zend_resolve_class_name(trait_name, &opline->extended_value, 0 TSRMLS_CC);
+	opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_TRAIT;
+	opline->op2 = *trait_name;
+	CG(active_class_entry)->num_traits++;
+}
+/* }}} */
+
 ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, const char *src1, int src1_length, const char *src2, int src2_length, int internal) /* {{{ */
 {
 	char *prop_name;
@@ -4423,6 +5049,33 @@
 }
 /* }}} */
 
+void zend_init_list(void *result, void *item TSRMLS_DC) /* {{{ */
+{
+	void** list = emalloc(sizeof(void*) * 2);
+	
+	list[0] = item;
+	list[1] = NULL;
+	
+	*(void**)result = list;
+}
+/* }}} */
+
+void zend_add_to_list(void *result, void *item TSRMLS_DC) /* {{{ */
+{
+	void** list = *(void**)result;
+	size_t n = 0;
+	
+	while (list && list[n]) { n++; }
+	
+	list = erealloc(list, sizeof(void*) * (n+2));
+	
+	list[n]   = item;
+	list[n+1] = NULL;
+	
+	*(void**)result = list;
+}
+/* }}} */
+
 void zend_do_fetch_static_variable(znode *varname, const znode *static_assignment, int fetch_type TSRMLS_DC) /* {{{ */
 {
 	zval *tmp;
@@ -5262,6 +5915,10 @@
 		ce->parent = NULL;
 		ce->num_interfaces = 0;
 		ce->interfaces = NULL;
+		ce->num_traits = 0;
+		ce->traits = NULL;
+		ce->trait_aliases = NULL;
+		ce->trait_precedences = 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.391
diff -u -r1.391 zend_compile.h
--- Zend/zend_compile.h	31 Dec 2008 11:12:28 -0000	1.391
+++ Zend/zend_compile.h	18 Jan 2009 13:48:35 -0000
@@ -120,6 +120,7 @@
 #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS	0x20
 #define ZEND_ACC_FINAL_CLASS	            0x40
 #define ZEND_ACC_INTERFACE		            0x80
+#define ZEND_ACC_TRAIT						0x120
 
 /* op_array flags */
 #define ZEND_ACC_INTERACTIVE				0x10
@@ -150,6 +151,7 @@
 
 /* class implement interface(s) flag */
 #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000
+#define ZEND_ACC_IMPLEMENT_TRAITS	  0x400000
 
 #define ZEND_ACC_CLOSURE              0x100000
 
@@ -457,6 +459,21 @@
 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);
 
+/* Trait related functions */
+void zend_add_trait_precedence(znode *precedence_znode TSRMLS_DC);
+void zend_add_trait_alias(znode *alias_znode TSRMLS_DC);
+
+
+//void zend_do_implements_trait(znode *interface_znode /*, znode* aliases */ TSRMLS_DC);
+//ZEND_API void zend_do_implement_trait(zend_class_entry *ce, const zend_class_entry *trait 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, const znode* trait_alias TSRMLS_DC);
+void add_trait_alias(znode* result, const znode* trait_alias TSRMLS_DC);
+void init_trait_alias(znode* result, const znode* method_name, const znode* alias, const 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);
 ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC);
@@ -507,6 +524,11 @@
 void zend_do_new_list_begin(TSRMLS_D);
 void zend_do_new_list_end(TSRMLS_D);
 
+/* Functions for a null terminated pointer list, used for traits parsing and compilation */
+void zend_init_list(void *result, void *item TSRMLS_DC);
+void zend_add_to_list(void *result, void *item TSRMLS_DC);
+
+
 void zend_do_cast(znode *result, const znode *expr, int type TSRMLS_DC);
 void zend_do_include_or_eval(int type, znode *result, const znode *op1 TSRMLS_DC);
 
@@ -660,6 +682,7 @@
 #define ZEND_FETCH_CLASS_AUTO		5
 #define ZEND_FETCH_CLASS_INTERFACE	6
 #define ZEND_FETCH_CLASS_STATIC		7
+#define ZEND_FETCH_CLASS_TRAIT		14
 #define ZEND_FETCH_CLASS_MASK         0x0f
 #define ZEND_FETCH_CLASS_NO_AUTOLOAD  0x80
 #define ZEND_FETCH_CLASS_SILENT       0x0100
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.471
diff -u -r1.471 zend_execute_API.c
--- Zend/zend_execute_API.c	2 Jan 2009 13:14:17 -0000	1.471
+++ Zend/zend_execute_API.c	18 Jan 2009 13:48:35 -0000
@@ -1641,6 +1641,8 @@
 			if (!silent && !EG(exception)) {
 				if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) {
 					zend_error(E_ERROR, "Interface '%R' not found", type, class_name);
+				} else if (fetch_type == ZEND_FETCH_CLASS_TRAIT) {
+					zend_error(E_ERROR, "Trait '%R' not found", type, class_name);
 				} else {
 					zend_error(E_ERROR, "Class '%R' not found", type, class_name);
 				}
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.214
diff -u -r1.214 zend_language_parser.y
--- Zend/zend_language_parser.y	31 Dec 2008 11:09:46 -0000	1.214
+++ Zend/zend_language_parser.y	18 Jan 2009 13:48:36 -0000
@@ -113,6 +113,8 @@
 %token T_CATCH
 %token T_THROW
 %token T_USE
+%token T_USES
+%token T_INSTEAD
 %token T_GLOBAL
 %right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
 %token T_VAR
@@ -121,6 +123,7 @@
 %token T_EMPTY
 %token T_HALT_COMPILER
 %token T_CLASS
+%token T_TRAIT
 %token T_INTERFACE
 %token T_EXTENDS
 %token T_IMPLEMENTS
@@ -331,6 +334,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; }
 ;
 
@@ -516,10 +520,67 @@
 class_statement:
 		variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';'
 	|	class_constant_declaration ';'
+	|	trait_use_statement
 	|	method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '('
 			parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
 ;
 
+trait_use_statement:
+		T_USE trait_list trait_adaptations
+;
+
+trait_list:
+		fully_qualified_class_name						{ zend_do_implements_trait(&$1 TSRMLS_CC); }
+	|	trait_list ',' fully_qualified_class_name		{ zend_do_implements_trait(&$3 TSRMLS_CC); }
+;
+
+trait_adaptations:
+		';'
+	|	'{' trait_adaptation_list '}'
+;
+
+trait_adaptation_list:
+		/* empty */
+	|	non_empty_trait_adaptation_list
+;
+
+non_empty_trait_adaptation_list:
+		trait_adaptation_statement
+	|	non_empty_trait_adaptation_list trait_adaptation_statement
+;
+
+trait_adaptation_statement:
+		trait_precedence ';'								{ zend_add_trait_precedence(&$1 TSRMLS_CC); }
+	|	trait_alias ';'										{ zend_add_trait_alias(&$1 TSRMLS_CC); }
+;
+
+trait_precedence:
+	trait_method_reference_fully_qualified T_INSTEAD trait_reference_list	{ zend_prepare_trait_precedence(&$$, &$1, &$3 TSRMLS_CC); }
+;
+
+trait_reference_list:
+		fully_qualified_class_name									{ zend_init_list(&$$.u.var, Z_UNIVAL($1.u.constant).v TSRMLS_CC); }
+	|	trait_reference_list ',' fully_qualified_class_name			{ zend_add_to_list(&$1.u.var, Z_UNIVAL($3.u.constant).v TSRMLS_CC); $$ = $1; }
+;
+
+trait_method_reference:
+		T_STRING													{ zend_prepare_reference(&$$, NULL, &$1 TSRMLS_CC); }
+	|	trait_method_reference_fully_qualified						{ $$ = $1; }
+;
+
+trait_method_reference_fully_qualified:
+	fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING		{ zend_prepare_reference(&$$, &$1, &$3 TSRMLS_CC); }
+;
+
+trait_alias:
+		trait_method_reference T_AS trait_modifiers T_STRING		{ zend_prepare_trait_alias(&$$, &$1, &$3, &$4 TSRMLS_CC); }
+	|	trait_method_reference T_AS member_modifier					{ zend_prepare_trait_alias(&$$, &$1, &$3, NULL TSRMLS_CC); }
+;
+
+trait_modifiers:
+		/* empty */					{ Z_LVAL($$.u.constant) = 0x0; } /* No change of methods visibility */
+	|	member_modifier	{ $$ = $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.200
diff -u -r1.200 zend_language_scanner.l
--- Zend/zend_language_scanner.l	9 Jan 2009 17:20:56 -0000	1.200
+++ Zend/zend_language_scanner.l	18 Jan 2009 13:48:37 -0000
@@ -1543,6 +1543,10 @@
 	return T_INTERFACE;
 }
 
+<ST_IN_SCRIPTING>"trait" {
+	return T_TRAIT;
+}
+
 <ST_IN_SCRIPTING>"extends" {
 	return T_EXTENDS;
 }
@@ -1669,6 +1673,10 @@
 	return T_USE;
 }
 
+<ST_IN_SCRIPTING>"instead" {
+        return T_INSTEAD;
+}     
+
 <ST_IN_SCRIPTING>"global" {
 	return T_GLOBAL;
 }
Index: Zend/zend_opcode.c
===================================================================
RCS file: /repository/ZendEngine2/zend_opcode.c,v
retrieving revision 1.136
diff -u -r1.136 zend_opcode.c
--- Zend/zend_opcode.c	31 Dec 2008 11:12:29 -0000	1.136
+++ Zend/zend_opcode.c	18 Jan 2009 13:48:37 -0000
@@ -230,9 +230,50 @@
 			if (ce->num_interfaces > 0 && ce->interfaces) {
 				efree(ce->interfaces);
 			}
+			if (ce->num_traits > 0 && ce->traits) {
+				efree(ce->traits);
+			}
 			if (ce->doc_comment.v) {
 				efree(ce->doc_comment.v);
 			}
+			if (ce->trait_aliases) {
+				size_t i = 0;
+				while (ce->trait_aliases[i]) {
+					if (ce->trait_aliases[i]->trait_method) {
+						if (ce->trait_aliases[i]->trait_method->method_name.v) {
+							efree(ce->trait_aliases[i]->trait_method->method_name.v);
+						}
+						if (ce->trait_aliases[i]->trait_method->class_name.v) {
+							efree(ce->trait_aliases[i]->trait_method->class_name.v);
+						}
+						efree(ce->trait_aliases[i]->trait_method);
+					}
+					if (ce->trait_aliases[i]->alias.v) {
+						efree(ce->trait_aliases[i]->alias.v);
+					}
+					efree(ce->trait_aliases[i]);
+					i++;
+				}
+				efree(ce->trait_aliases);
+			}
+			
+			if (ce->trait_precedences) {
+				size_t i = 0;
+				while (ce->trait_precedences[i]) {
+					efree(ce->trait_precedences[i]->trait_method->method_name.v);
+					efree(ce->trait_precedences[i]->trait_method->class_name.v);
+					efree(ce->trait_precedences[i]->trait_method);
+					
+					if (ce->trait_precedences[i]->exclude_from_classes) {
+						efree(ce->trait_precedences[i]->exclude_from_classes);
+					}
+					
+					efree(ce->trait_precedences[i]);
+					i++;
+				}
+				efree(ce->trait_precedences);
+			}
+
 			efree(ce);
 			break;
 		case ZEND_INTERNAL_CLASS:
@@ -245,6 +286,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.v) {
 				free(ce->doc_comment.v);
 			}
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.255
diff -u -r1.255 zend_vm_def.h
--- Zend/zend_vm_def.h	15 Jan 2009 08:49:11 -0000	1.255
+++ Zend/zend_vm_def.h	18 Jan 2009 13:48:38 -0000
@@ -4432,6 +4432,33 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+ZEND_VM_HANDLER(154, ZEND_ADD_TRAIT, ANY, ANY)
+{
+	// TODO: is this still used? if so, needs to be updated from zend_vm_execute.h
+	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(155, ZEND_BIND_TRAITS, ANY, ANY)
+{
+	// TODO: is this still used? if so, needs to be updated from zend_vm_execute.h
+	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.259
diff -u -r1.259 zend_vm_execute.h
--- Zend/zend_vm_execute.h	15 Jan 2009 08:49:11 -0000	1.259
+++ Zend/zend_vm_execute.h	18 Jan 2009 13:48:47 -0000
@@ -911,6 +911,32 @@
 	ZEND_VM_NEXT_OPCODE();
 }
 
+static int ZEND_FASTCALL 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 = zend_u_fetch_class(Z_TYPE(opline->op2.u.constant), Z_UNIVAL(opline->op2.u.constant), Z_UNILEN(opline->op2.u.constant), opline->extended_value TSRMLS_CC);
+	
+	if (!(trait->ce_flags & ZEND_ACC_TRAIT)) {
+		zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ce->name, trait->name);
+	}
+	
+	zend_do_implement_trait(ce, trait TSRMLS_CC);
+	
+	ZEND_VM_NEXT_OPCODE();
+}
+
+static int ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	// TODO: make sure this code is removed if it is dead
+	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_FASTCALL  ZEND_FETCH_CLASS_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	zend_op *opline = EX(opline);
@@ -35433,6 +35459,56 @@
   	ZEND_NULL_HANDLER,
   	ZEND_NULL_HANDLER,
   	ZEND_NULL_HANDLER,
+  	ZEND_ADD_TRAIT_SPEC_HANDLER, // STEFAN added for opcode 154 and 155
+	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.75
diff -u -r1.75 zend_vm_opcodes.h
--- Zend/zend_vm_opcodes.h	31 Dec 2008 11:12:29 -0000	1.75
+++ Zend/zend_vm_opcodes.h	18 Jan 2009 13:48:47 -0000
@@ -154,3 +154,5 @@
 #define ZEND_U_NORMALIZE                     151
 #define ZEND_JMP_SET                         152
 #define ZEND_DECLARE_LAMBDA_FUNCTION         153
+#define ZEND_ADD_TRAIT			     154
+#define ZEND_BIND_TRAITS		     155
