Raw version
? tests/classes/late_static_binding_001.phpt
? tests/classes/late_static_binding_002.phpt
? tests/classes/late_static_binding_003.phpt
? tests/classes/late_static_binding_004.phpt
? tests/classes/late_static_binding_005.phpt
? tests/classes/late_static_binding_006.phpt
? tests/classes/late_static_binding_007.phpt
Index: Zend/zend_builtin_functions.c
===================================================================
RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v
retrieving revision 1.347
diff -u -p -r1.347 zend_builtin_functions.c
--- Zend/zend_builtin_functions.c	8 Aug 2007 13:32:58 -0000	1.347
+++ Zend/zend_builtin_functions.c	20 Aug 2007 02:15:06 -0000
@@ -44,6 +44,7 @@ static ZEND_FUNCTION(define);
 static ZEND_FUNCTION(defined);
 static ZEND_FUNCTION(get_class);
 static ZEND_FUNCTION(get_parent_class);
+static ZEND_FUNCTION(get_called_class);
 static ZEND_FUNCTION(method_exists);
 static ZEND_FUNCTION(property_exists);
 static ZEND_FUNCTION(class_exists);
@@ -104,6 +105,7 @@ static zend_function_entry builtin_funct
 	ZEND_FE(defined,			NULL)
 	ZEND_FE(get_class,			NULL)
 	ZEND_FE(get_parent_class,	NULL)
+	ZEND_FE(get_called_class,	NULL)
 	ZEND_FE(method_exists,		NULL)
 	ZEND_FE(property_exists,	NULL)
 	ZEND_FE(class_exists,		NULL)
@@ -658,6 +660,30 @@ ZEND_FUNCTION(get_parent_class)
 }
 /* }}} */

+/* {{{ proto string get_called_class() U
+   Retrieves the class name that were initially called. @see static:: */
+ZEND_FUNCTION(get_called_class)
+{
+	zend_class_entry *lsb_scope;
+
+	if (ZEND_NUM_ARGS()) {
+		ZEND_WRONG_PARAM_COUNT();
+	}
+
+	if (!EG(scope)) {
+		RETURN_FALSE;
+	}
+
+	lsb_scope = zend_fetch_class_lsb(EG(scope) TSRMLS_CC);
+
+	if (lsb_scope) {
+		RETURN_TEXTL(lsb_scope->name, lsb_scope->name_length, 1);
+	} else {
+		RETURN_FALSE;
+	}
+}
+/* }}} */
+
 static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass) /* {{{ */
 {
 	zval **obj, **class_name;
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.761
diff -u -p -r1.761 zend_compile.c
--- Zend/zend_compile.c	17 Aug 2007 12:05:19 -0000	1.761
+++ Zend/zend_compile.c	20 Aug 2007 02:15:13 -0000
@@ -1687,6 +1687,7 @@ void zend_do_fetch_class(znode *result,
 		fetch_type = zend_get_class_fetch_type(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant));
 		switch (fetch_type) {
 			case ZEND_FETCH_CLASS_SELF:
+			case ZEND_FETCH_CLASS_LATE:
 			case ZEND_FETCH_CLASS_PARENT:
 				SET_UNUSED(opline->op2);
 				opline->extended_value = fetch_type;
@@ -3165,7 +3166,9 @@ void zend_do_begin_class_declaration(zno

 	if ((lcname_len == sizeof("self")-1 &&
 	     ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "self", sizeof("self")-1)) ||
-	    (lcname_len == sizeof("parent")-1 &&
+	    (lcname_len == sizeof("static")-1 &&
+	     ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "static", sizeof("static")-1)) ||
+		(lcname_len == sizeof("parent")-1 &&
 	     ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "parent", sizeof("parent")-1))) {
 		efree(lcname.v);
 		zend_error(E_COMPILE_ERROR, "Cannot use '%R' as class name as it is reserved", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant));
@@ -3199,6 +3202,9 @@ void zend_do_begin_class_declaration(zno

 	if (parent_class_name && parent_class_name->op_type != IS_UNUSED) {
 		switch (parent_class_name->u.EA.type) {
+			case ZEND_FETCH_CLASS_LATE:
+				zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved");
+				break;
 			case ZEND_FETCH_CLASS_SELF:
 				zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved");
 				break;
@@ -3311,6 +3317,9 @@ void zend_do_implements_interface(znode

 	zend_do_fetch_class(&interface_node, interface_name TSRMLS_CC);
 	switch (interface_node.u.EA.type) {
+		case ZEND_FETCH_CLASS_LATE:
+			zend_error(E_COMPILE_ERROR, "Cannot use 'static' as interface name as it is reserved");
+			break;
 		case ZEND_FETCH_CLASS_SELF:
 			zend_error(E_COMPILE_ERROR, "Cannot use 'self' as interface name as it is reserved");
 			break;
@@ -4771,6 +4780,9 @@ int zend_get_class_fetch_type(zend_uchar
 	if ((class_name_len == sizeof("self")-1) &&
 	    ZEND_U_EQUAL(type, class_name, class_name_len, "self", sizeof("self")-1)) {
 		return ZEND_FETCH_CLASS_SELF;
+	} else if ((class_name_len == sizeof("static")-1) &&
+	    ZEND_U_EQUAL(type, class_name, class_name_len, "static", sizeof("static")-1)) {
+		return ZEND_FETCH_CLASS_LATE;
 	} else if ((class_name_len == sizeof("parent")-1) &&
 	    ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) {
 		return ZEND_FETCH_CLASS_PARENT;
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.362
diff -u -p -r1.362 zend_compile.h
--- Zend/zend_compile.h	27 Jul 2007 13:41:35 -0000	1.362
+++ Zend/zend_compile.h	20 Aug 2007 02:15:14 -0000
@@ -308,6 +308,8 @@ struct _zend_execute_data {
 	HashTable *symbol_table;
 	struct _zend_execute_data *prev_execute_data;
 	zval *old_error_reporting;
+	int lsb_push_number;
+	int lsb_break;
 };

 #define EX(element) execute_data.element
@@ -631,6 +633,7 @@ int zendlex(znode *zendlval TSRMLS_DC);
 #define ZEND_FETCH_CLASS_GLOBAL		4
 #define ZEND_FETCH_CLASS_AUTO		5
 #define ZEND_FETCH_CLASS_INTERFACE	6
+#define ZEND_FETCH_CLASS_LATE		7
 #define ZEND_FETCH_CLASS_FLAGS        0xF0
 #define ZEND_FETCH_CLASS_NO_NORMALIZE 0x10
 #define ZEND_FETCH_CLASS_RT_NS_CHECK  0x20
Index: Zend/zend_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_execute.h,v
retrieving revision 1.108
diff -u -p -r1.108 zend_execute.h
--- Zend/zend_execute.h	21 Jul 2007 00:34:41 -0000	1.108
+++ Zend/zend_execute.h	20 Aug 2007 02:15:14 -0000
@@ -194,6 +194,7 @@ ZEND_API void zend_unset_timeout(TSRMLS_
 ZEND_API void zend_timeout(int dummy);
 ZEND_API zend_class_entry *zend_fetch_class(char *class_name, uint class_name_len, int fetch_type TSRMLS_DC);
 ZEND_API zend_class_entry *zend_u_fetch_class(zend_uchar type, zstr class_name, uint class_name_len, int fetch_type TSRMLS_DC);
+ZEND_API zend_class_entry *zend_fetch_class_lsb(zend_class_entry *scope TSRMLS_DC);
 void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC);

 #ifdef ZEND_WIN32
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.410
diff -u -p -r1.410 zend_execute_API.c
--- Zend/zend_execute_API.c	27 Jul 2007 13:41:35 -0000	1.410
+++ Zend/zend_execute_API.c	20 Aug 2007 02:15:15 -0000
@@ -159,7 +159,11 @@ void init_executor(TSRMLS_D) /* {{{ */
 	EG(in_autoload) = NULL;
 	EG(autoload_func) = NULL;

+	EG(last_fetched_class) = NULL;
+	zend_ptr_stack_init(&EG(class_call_stack));
+
 	zend_ptr_stack_init(&EG(argument_stack));
+
 	zend_ptr_stack_push(&EG(argument_stack), (void *) NULL);

 	zend_u_hash_init(&EG(symbol_table), 50, NULL, ZVAL_PTR_DTOR, 0, UG(unicode));
@@ -307,6 +311,8 @@ void shutdown_executor(TSRMLS_D) /* {{{
 		}
 		zend_hash_apply(EG(class_table), (apply_func_t) zend_cleanup_class_data TSRMLS_CC);

+		zend_ptr_stack_destroy(&EG(class_call_stack));
+
 		zend_ptr_stack_destroy(&EG(argument_stack));

 		/* Destroy all op arrays */
@@ -1021,6 +1027,8 @@ int zend_call_function(zend_fcall_info *
 	current_scope = EG(scope);
 	EG(scope) = calling_scope;

+	EG(last_fetched_class) = calling_scope;
+
 	current_this = EG(This);

 	if (fci->object_pp) {
@@ -1072,7 +1080,11 @@ int zend_call_function(zend_fcall_info *
 		EG(return_value_ptr_ptr) = fci->retval_ptr_ptr;
 		EG(active_op_array) = (zend_op_array *) EX(function_state).function;
 		original_opline_ptr = EG(opline_ptr);
+
+		zend_ptr_stack_push(&EG(class_call_stack), calling_scope);
 		zend_execute(EG(active_op_array) TSRMLS_CC);
+		zend_ptr_stack_pop(&EG(class_call_stack));
+
 		if (!fci->symbol_table) {
 			zend_hash_destroy(EG(active_symbol_table));
 			FREE_HASHTABLE(EG(active_symbol_table));
@@ -1647,6 +1659,19 @@ void zend_unset_timeout(TSRMLS_D) /* {{{
 }
 /* }}} */

+ZEND_API zend_class_entry *zend_fetch_class_lsb(zend_class_entry *scope TSRMLS_DC) /* {{{ */
+{
+	zend_class_entry *last_scope = EG(class_call_stack).elements[EG(class_call_stack).top-1];
+
+	if (last_scope == NULL || instanceof_function(last_scope, scope TSRMLS_CC) != 1) {
+		return scope;
+	} else {
+		return last_scope;
+	}
+
+}
+/* }}} */
+
 ZEND_API zend_class_entry *zend_u_fetch_class(zend_uchar type, zstr class_name, uint class_name_len, int fetch_type TSRMLS_DC) /* {{{ */
 {
 	zend_class_entry **pce;
@@ -1660,10 +1685,18 @@ ZEND_API zend_class_entry *zend_u_fetch_

 check_fetch_type:
 	switch (fetch_type) {
+		case ZEND_FETCH_CLASS_LATE:
+			if (!EG(scope)) {
+				zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
+			}
+			zend_class_entry *lsb_scope = zend_fetch_class_lsb(EG(scope) TSRMLS_CC);
+			EG(last_fetched_class) = lsb_scope;
+			return lsb_scope;
 		case ZEND_FETCH_CLASS_SELF:
 			if (!EG(scope)) {
 				zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
 			}
+			EG(last_fetched_class) = EG(scope);
 			return EG(scope);
 		case ZEND_FETCH_CLASS_PARENT:
 			if (!EG(scope)) {
@@ -1672,6 +1705,7 @@ check_fetch_type:
 			if (!EG(scope)->parent) {
 				zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
 			}
+			EG(last_fetched_class) = EG(scope)->parent;
 			return EG(scope)->parent;
 		case ZEND_FETCH_CLASS_AUTO: {
 				if (do_normalize) {
@@ -1703,6 +1737,7 @@ check_fetch_type:
 						if (lcname.v != class_name.v) {
 							efree(lcname.v);
 						}
+						EG(last_fetched_class) = *pce;
 						return *pce;
 					}
 				}
@@ -1715,6 +1750,7 @@ check_fetch_type:
 						if (lcname.v != class_name.v) {
 							efree(lcname.v);
 						}
+						EG(last_fetched_class) = *pce;
 						return *pce;
 					}
 				}
@@ -1730,11 +1766,13 @@ check_fetch_type:
 		if (lcname.v != class_name.v) {
 			efree(lcname.v);
 		}
+		EG(last_fetched_class) = NULL;
 		return NULL;
 	} else {
 		if (lcname.v != class_name.v) {
 			efree(lcname.v);
 		}
+		EG(last_fetched_class) = *pce;
 		return *pce;
 	}
 }
Index: Zend/zend_globals.h
===================================================================
RCS file: /repository/ZendEngine2/zend_globals.h,v
retrieving revision 1.168
diff -u -p -r1.168 zend_globals.h
--- Zend/zend_globals.h	12 Jul 2007 09:23:48 -0000	1.168
+++ Zend/zend_globals.h	20 Aug 2007 02:15:16 -0000
@@ -160,6 +160,9 @@ struct _zend_executor_globals {
 	zend_function_state *function_state_ptr;
 	zend_ptr_stack arg_types_stack;

+	zend_ptr_stack    class_call_stack;
+	zend_class_entry *last_fetched_class;
+
 	/* symbol table cache */
 	HashTable *symtable_cache[SYMTABLE_CACHE_SIZE];
 	HashTable **symtable_cache_limit;
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.187
diff -u -p -r1.187 zend_language_parser.y
--- Zend/zend_language_parser.y	2 Aug 2007 21:53:53 -0000	1.187
+++ Zend/zend_language_parser.y	20 Aug 2007 02:15:17 -0000
@@ -667,6 +667,7 @@ fully_qualified_class_name:
 		T_STRING { $$ = $1; }
 	|	T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, NULL, &$2 TSRMLS_CC); }
 	|	fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); }
+	|	T_STATIC { znode tmp; tmp.op_type = IS_CONST; ZVAL_STRINGL(&tmp.u.constant, "static", sizeof("static")-1, 1);  INIT_PZVAL(&tmp.u.constant); $$ = tmp; }
 ;


Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.177
diff -u -p -r1.177 zend_vm_def.h
--- Zend/zend_vm_def.h	17 Aug 2007 12:05:19 -0000	1.177
+++ Zend/zend_vm_def.h	20 Aug 2007 02:15:22 -0000
@@ -1754,6 +1754,10 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CA
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -2662,6 +2666,11 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
 		EX(object) = object_zval;
 		EX(fbc) = constructor;

+		if (constructor->common.fn_flags && constructor->type == ZEND_USER_FUNCTION) {
+			/* Affect the lsb_push_number of the next execute data */
+			EG(current_execute_data)->lsb_break = 1;
+		}
+
 		ZEND_VM_NEXT_OPCODE();
 	}
 }
Index: Zend/zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.181
diff -u -p -r1.181 zend_vm_execute.h
--- Zend/zend_vm_execute.h	17 Aug 2007 12:05:19 -0000	1.181
+++ Zend/zend_vm_execute.h	20 Aug 2007 02:15:51 -0000
@@ -82,6 +82,27 @@ ZEND_API void execute(zend_op_array *op_
 	EX(function_state).function_symbol_table = NULL;
 #endif

+	execute_data.lsb_push_number = 0;
+	execute_data.lsb_break = 0;
+
+	if (EX(prev_execute_data) && EX(prev_execute_data)->lsb_break) {
+			/* Detect that last execute_data triggered a break */
+			zend_ptr_stack_push(&EG(class_call_stack), NULL);
+			execute_data.lsb_push_number++;
+			EX(prev_execute_data)->lsb_break = 0;
+	}
+
+	if (EG(last_fetched_class) == EX(function_state).function->common.scope) {
+		/* No fallback */
+		zend_ptr_stack_push(&EG(class_call_stack), NULL);
+		zend_ptr_stack_push(&EG(class_call_stack), EG(scope));
+		execute_data.lsb_push_number += 2;
+	} else if (EX(function_state).function->common.scope != NULL) {
+		/* we are executing a method, static or not check scope */
+		zend_ptr_stack_push(&EG(class_call_stack), EG(last_fetched_class));
+		execute_data.lsb_push_number += 1;
+	}
+
 	while (1) {
 #ifdef ZEND_WIN32
 		if (EG(timed_out)) {
@@ -90,6 +111,12 @@ ZEND_API void execute(zend_op_array *op_
 #endif

 		if (EX(opline)->handler(&execute_data TSRMLS_CC) > 0) {
+			if (execute_data.lsb_push_number) {
+				/* clean block separation(s) */
+				while(--execute_data.lsb_push_number >= 0) {
+					zend_ptr_stack_pop(&EG(class_call_stack));
+				}
+			}
       return;
 		}

@@ -437,6 +464,11 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OP
 		EX(object) = object_zval;
 		EX(fbc) = constructor;

+		if (constructor->common.fn_flags && constructor->type == ZEND_USER_FUNCTION) {
+			/* Affect the lsb_push_number of the next execute data */
+			EG(current_execute_data)->lsb_break = 1;
+		}
+
 		ZEND_VM_NEXT_OPCODE();
 	}
 }
@@ -5804,6 +5836,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -6253,6 +6289,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -6704,6 +6744,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -7248,6 +7292,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -10000,6 +10048,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -11702,6 +11754,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -13397,6 +13453,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -15636,6 +15696,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -16960,6 +17024,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -18023,6 +18091,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -19040,6 +19112,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -20322,6 +20398,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -23092,6 +23172,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -24627,6 +24711,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -26201,6 +26289,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
@@ -28206,6 +28298,10 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
 			zend_error_noreturn(E_ERROR, "Object does not support method calls");
 		}

+		if (Z_OBJCE_P(EX(object))) {
+			EG(last_fetched_class) = Z_OBJCE_P(EX(object));
+		}
+
 		/* First, locate the function. */
 		EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
 		if (!EX(fbc)) {
Index: Zend/zend_vm_execute.skl
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.skl,v
retrieving revision 1.7
diff -u -p -r1.7 zend_vm_execute.skl
--- Zend/zend_vm_execute.skl	21 Jul 2007 00:34:41 -0000	1.7
+++ Zend/zend_vm_execute.skl	20 Aug 2007 02:15:51 -0000
@@ -53,6 +53,27 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
 	EX(function_state).function_symbol_table = NULL;
 #endif

+	execute_data.lsb_push_number = 0;
+	execute_data.lsb_break = 0;
+
+	if (EX(prev_execute_data) && EX(prev_execute_data)->lsb_break) {
+			/* Detect that last execute_data triggered a break */
+			zend_ptr_stack_push(&EG(class_call_stack), NULL);
+			execute_data.lsb_push_number++;
+			EX(prev_execute_data)->lsb_break = 0;
+	}
+
+	if (EG(last_fetched_class) == EX(function_state).function->common.scope) {
+		/* No fallback */
+		zend_ptr_stack_push(&EG(class_call_stack), NULL);
+		zend_ptr_stack_push(&EG(class_call_stack), EG(scope));
+		execute_data.lsb_push_number += 2;
+	} else if (EX(function_state).function->common.scope != NULL) {
+		/* we are executing a method, static or not check scope */
+		zend_ptr_stack_push(&EG(class_call_stack), EG(last_fetched_class));
+		execute_data.lsb_push_number += 1;
+	}
+
 	while (1) {
     {%ZEND_VM_CONTINUE_LABEL%}
 #ifdef ZEND_WIN32
@@ -62,6 +83,12 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
 #endif

 		{%ZEND_VM_DISPATCH%} {
+			if (execute_data.lsb_push_number) {
+				/* clean block separation(s) */
+				while(--execute_data.lsb_push_number >= 0) {
+					zend_ptr_stack_pop(&EG(class_call_stack));
+				}
+			}
       {%INTERNAL_EXECUTOR%}
 		}

Index: tests/classes/late_static_binding_008.phpt
===================================================================
RCS file: tests/classes/late_static_binding_008.phpt
diff -N tests/classes/late_static_binding_008.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/classes/late_static_binding_008.phpt	20 Aug 2007 02:15:52 -0000
@@ -0,0 +1,45 @@
+--TEST--
+ZE2 Late Static Binding with get_called_class()
+--FILE--
+<?php
+
+class TestChild extends TestParent {
+}
+
+class TestParent {
+
+    public function __get($var) {
+        echo get_called_class()."\n";
+    }
+
+    public function __set($var, $val) {
+        echo get_called_class()."\n";
+    }
+
+    public function __call($name, $args) {
+        echo get_called_class()."\n";
+    }
+
+    public static function test() {
+        echo get_called_class()."\n";
+    }
+}
+$o = new TestChild;
+$o->test();
+$o->a = "b";
+echo $o->a;
+
+TestParent::test();
+TestChild::test();
+
+var_dump(get_called_class());
+?>
+==DONE==
+--EXPECTF--
+TestChild
+TestChild
+TestChild
+TestParent
+TestChild
+bool(false)
+==DONE==
Index: tests/classes/late_static_binding_009.phpt
===================================================================
RCS file: tests/classes/late_static_binding_009.phpt
diff -N tests/classes/late_static_binding_009.phpt
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/classes/late_static_binding_009.phpt	20 Aug 2007 02:15:52 -0000
@@ -0,0 +1,49 @@
+--TEST--
+ZE2 Late Static Binding with scope paths
+--FILE--
+<?php
+
+class A {
+
+    public static function test1() {
+        C::test1();
+    }
+    public static function test2() {
+        echo get_called_class()."\n";
+    }
+}
+
+class B extends A {
+    public static function test1() {
+        A::test1();
+    }
+    public static function test2() {
+        C::test2();
+    }
+}
+
+class C extends A {
+
+    public static function test1() {
+        echo get_called_class()."\n";
+    }
+
+    public static function test2() {
+        A::test2();
+    }
+}
+
+//   A
+//  / \
+// B   C
+
+// code path 2: B -> C -> A
+B::test2();
+// code path 1: B -> A -> C
+B::test1();
+?>
+==DONE==
+--EXPECTF--
+A
+C
+==DONE==