Attached.

Thanks. Dmitry.

> -----Original Message-----
> From: Etienne Kneuss [mailto:[EMAIL PROTECTED] 
> Sent: Sunday, September 09, 2007 11:02 PM
> To: Dmitry Stogov
> Cc: internals@lists.php.net
> Subject: Re: [PHP-DEV] [patch] Late static bindings (LSB)
> 
> 
> Hello,
> 
> sorry for the late reply, I am on vacations these weeks and 
> only have a 
> sparse access to web.
> I was aware that my patch missed supports for callbacks, and 
> let it that 
> way on purpose as I
> planned to do some cleanup work on callbacks.
> 
> It looks like you placed the work necessary to have LSB in a 
> different 
> place than mine,
> generating more occurences and hence a quite bigger patch 
> size. I'd like 
> to see what implications it has.
> 
> Sadly, the patch you gave me is not easily patchable with the current 
> HEAD, do you have an up to date version ?
> 
> Thanks in advance
> 
> Dmitry Stogov wrote:
> > Hi Etienne,
> >
> > We already have patch for late static binding that is very 
> similar to 
> > yours. If you have time, please compare them.
> > >From quick look I see that our patch more accurate (it supports 
> > >constants
> > and runtime function calls)
> > Does our patch miss something that your patch does?
> >
> > Thanks. Dmitry.
> >
> >   
> >> -----Original Message-----
> >> From: Etienne Kneuss [mailto:[EMAIL PROTECTED]
> >> Sent: Friday, August 24, 2007 5:19 PM
> >> To: internals@lists.php.net
> >> Subject: [PHP-DEV] [patch] Late static bindings (LSB)
> >>
> >>
> >> Hi internals,
> >>
> >> here is a patch that implements Late static bindinds in a way that
> >> minimizes the performance hits that were feared.
> >> There is no significant slowdown or memory usage increase 
> >> when running 
> >> Zend/bench.php, which I assume is a
> >> good enough bench for that kind of matter, as it involves a stupid 
> >> amount of (recursive) function calls.
> >>
> >> You can also find the patch here:
> >> 
> http://patches.colder.ch/Zend/late_static_bindings_take6.patch?markup
> >>
> >> Here is a document that describes its usage:
> >> http://colder.ch/news/08-24-2007/28/late-static-bindings-expl.html
> >>
> >> Regards,
> >>
> >> --
> >> Etienne Kneuss
> >> http://www.colder.ch
> >>
> >> Men never do evil so completely and cheerfully as
> >> when they do it from a religious conviction.
> >> -- Pascal
> >>
> >>
> >>     
> 
> 
> -- 
> Etienne Kneuss
> http://www.colder.ch
> 
> Men never do evil so completely and cheerfully as 
> when they do it from a religious conviction.
> -- Pascal
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php
> 
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.443
diff -u -p -d -r1.443 zend_API.c
--- Zend/zend_API.c     31 Aug 2007 12:36:00 -0000      1.443
+++ Zend/zend_API.c     10 Sep 2007 07:59:35 -0000
@@ -2860,6 +2860,9 @@ ZEND_API zend_bool zend_is_callable_ex(z
                                                        lcname_len == 
sizeof("parent")-1 &&
                                                        
ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "parent", sizeof("parent")-1)) 
{
                                                        ce = 
EG(active_op_array)->scope->parent;
+                                               } else if (lcname_len == 
sizeof("static")-1 &&
+                                                       
ZEND_U_EQUAL(Z_TYPE_PP(obj), lcname, lcname_len, "static", sizeof("static")-1)) 
{
+                                                       ce = EG(caller_scope);
                                                } else if 
(zend_u_lookup_class(Z_TYPE_PP(obj), Z_UNIVAL_PP(obj), Z_UNILEN_PP(obj), &pce 
TSRMLS_CC) == SUCCESS) {
                                                        ce = *pce;
                                                }
Index: Zend/zend_builtin_functions.c
===================================================================
RCS file: /repository/ZendEngine2/zend_builtin_functions.c,v
retrieving revision 1.350
diff -u -p -d -r1.350 zend_builtin_functions.c
--- Zend/zend_builtin_functions.c       30 Aug 2007 07:43:53 -0000      1.350
+++ Zend/zend_builtin_functions.c       10 Sep 2007 07:59:35 -0000
@@ -43,6 +43,7 @@ static ZEND_FUNCTION(error_reporting);
 static ZEND_FUNCTION(define);
 static ZEND_FUNCTION(defined);
 static ZEND_FUNCTION(get_class);
+static ZEND_FUNCTION(get_caller_class);
 static ZEND_FUNCTION(get_parent_class);
 static ZEND_FUNCTION(method_exists);
 static ZEND_FUNCTION(property_exists);
@@ -103,6 +104,7 @@ static zend_function_entry builtin_funct
        ZEND_FE(define,                         NULL)
        ZEND_FE(defined,                        NULL)
        ZEND_FE(get_class,                      NULL)
+       ZEND_FE(get_caller_class,       NULL)
        ZEND_FE(get_parent_class,       NULL)
        ZEND_FE(method_exists,          NULL)
        ZEND_FE(property_exists,        NULL)
@@ -614,6 +616,26 @@ ZEND_FUNCTION(get_class)
 }
 /* }}} */
 
+/* {{{ proto string get_caller_class()
+   Retrieves the class name */
+ZEND_FUNCTION(get_caller_class)
+{
+       int dup;
+
+       if (!ZEND_NUM_ARGS()) {
+               if (EG(caller_scope)) {
+                       RETURN_TEXTL(EG(caller_scope)->name, 
EG(caller_scope)->name_length, 1);
+               } else {
+                       zend_error(E_ERROR, "get_caller_class() called from 
outside a class");
+               }
+       } else {
+               ZEND_WRONG_PARAM_COUNT();
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+
 /* {{{ proto string get_parent_class([mixed object]) U
    Retrieves the parent class name for object or class or current scope. */
 ZEND_FUNCTION(get_parent_class)
Index: Zend/zend_compile.c
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.c,v
retrieving revision 1.767
diff -u -p -d -r1.767 zend_compile.c
--- Zend/zend_compile.c 5 Sep 2007 07:24:52 -0000       1.767
+++ Zend/zend_compile.c 10 Sep 2007 07:59:36 -0000
@@ -1702,6 +1702,7 @@ void zend_do_fetch_class(znode *result, 
                switch (fetch_type) {
                        case ZEND_FETCH_CLASS_SELF:
                        case ZEND_FETCH_CLASS_PARENT:
+                       case ZEND_FETCH_CLASS_STATIC:
                                SET_UNUSED(opline->op2);
                                opline->extended_value = fetch_type;
                                zval_dtor(&class_name->u.constant);
@@ -3220,6 +3221,9 @@ void zend_do_begin_class_declaration(zno
                        case ZEND_FETCH_CLASS_PARENT:
                                zend_error(E_COMPILE_ERROR, "Cannot use 
'parent' as class name as it is reserved");
                                break;
+                       case ZEND_FETCH_CLASS_STATIC:
+                               zend_error(E_COMPILE_ERROR, "Cannot use 
'static' as class name as it is reserved");
+                               break;
                        default:
                                break;
                }
@@ -3332,6 +3336,9 @@ void zend_do_implements_interface(znode 
                case ZEND_FETCH_CLASS_PARENT:
                        zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as 
interface name as it is reserved");
                        break;
+               case ZEND_FETCH_CLASS_STATIC:
+                       zend_error(E_COMPILE_ERROR, "Cannot use 'static' as 
interface 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];
@@ -4876,6 +4883,9 @@ int zend_get_class_fetch_type(zend_uchar
        } 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;
+       } 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_STATIC;
        } else {
                return ZEND_FETCH_CLASS_DEFAULT;
        }
Index: Zend/zend_compile.h
===================================================================
RCS file: /repository/ZendEngine2/zend_compile.h,v
retrieving revision 1.364
diff -u -p -d -r1.364 zend_compile.h
--- Zend/zend_compile.h 24 Aug 2007 13:50:52 -0000      1.364
+++ Zend/zend_compile.h 10 Sep 2007 07:59:36 -0000
@@ -300,6 +300,7 @@ struct _zend_execute_data {
        struct _zend_op *opline;
        zend_function_state function_state;
        zend_function *fbc; /* Function Being Called */
+       zend_class_entry *caller_scope;
        zend_op_array *op_array;
        zval *object;
        union _temp_variable *Ts;
@@ -632,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_STATIC                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_constants.c
===================================================================
RCS file: /repository/ZendEngine2/zend_constants.c,v
retrieving revision 1.99
diff -u -p -d -r1.99 zend_constants.c
--- Zend/zend_constants.c       25 Aug 2007 23:28:10 -0000      1.99
+++ Zend/zend_constants.c       10 Sep 2007 07:59:36 -0000
@@ -382,6 +382,14 @@ ZEND_API int zend_u_get_constant_ex(zend
                                ce = &scope->parent;
                        }
                        efree(lcname.v);
+               } else if (lcname_len == sizeof("static")-1 &&
+                          ZEND_U_EQUAL(type, lcname, lcname_len, "static", 
sizeof("static")-1)) {
+                       if (EG(caller_scope)) {
+                               ce = &EG(caller_scope);
+                       } else {
+                               zend_error(E_ERROR, "Cannot access static:: 
when no class scope is active");
+                       }
+                       efree(lcname.v);
                } else {
                        /* Check for namespace constant */
                        zstr nsname;
Index: Zend/zend_execute_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_execute_API.c,v
retrieving revision 1.414
diff -u -p -d -r1.414 zend_execute_API.c
--- Zend/zend_execute_API.c     30 Aug 2007 14:48:39 -0000      1.414
+++ Zend/zend_execute_API.c     10 Sep 2007 07:59:36 -0000
@@ -201,6 +201,7 @@ void init_executor(TSRMLS_D) /* {{{ */
        EG(exception) = NULL;
 
        EG(scope) = NULL;
+       EG(caller_scope) = NULL;
 
        EG(This) = NULL;
        
@@ -677,6 +678,7 @@ int zend_call_function(zend_fcall_info *
        zend_op_array *original_op_array;
        zend_op **original_opline_ptr;
        zend_class_entry *current_scope;
+       zend_class_entry *current_caller_scope;
        zend_class_entry *calling_scope = NULL;
        zend_class_entry *check_scope_or_static = NULL;
        zval *current_this;
@@ -785,6 +787,15 @@ int zend_call_function(zend_fcall_info *
                                        found = (*ce != NULL?SUCCESS:FAILURE);
                                        fci->object_pp = 
EG(This)?&EG(This):NULL;
                                        EX(object) = EG(This);
+                               } else if (Z_UNILEN_PP(fci->object_pp) == 
sizeof("static")-1 &&
+                                   ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), 
Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "static", 
sizeof("static")-1)) {
+                                       if (!EG(caller_scope)) {
+                                               zend_error(E_ERROR, "Cannot 
access static:: when no class scope is active");
+                                       }
+                                       ce = &(EG(caller_scope));
+                                       found = (*ce != NULL?SUCCESS:FAILURE);
+                                       fci->object_pp = 
EG(This)?&EG(This):NULL;
+                                       EX(object) = EG(This);
                                } else {
                                        zend_class_entry *scope;
                                        scope = EG(active_op_array) ? 
EG(active_op_array)->scope : NULL;
@@ -853,6 +864,9 @@ int zend_call_function(zend_fcall_info *
                        } else if (calling_scope && clen == sizeof("parent") - 
1 && 
                            ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, 
clen, "parent", sizeof("parent")-1)) {
                                ce_child = EG(active_op_array) && 
EG(active_op_array)->scope ? EG(scope)->parent : NULL;
+                       } else if (clen == sizeof("static") - 1 && 
+                           ZEND_U_EQUAL(Z_TYPE_P(fci->function_name), lcname, 
clen, "static", sizeof("static")-1)) {
+                               ce_child = EG(caller_scope);
                        } else if 
(zend_u_lookup_class_ex(Z_TYPE_P(fci->function_name), lcname, clen, 1, 0, &pce 
TSRMLS_CC) == SUCCESS) {
                                ce_child = *pce;
                        }
@@ -1029,6 +1043,16 @@ int zend_call_function(zend_fcall_info *
 
        current_this = EG(This);
 
+       current_caller_scope = EG(caller_scope);
+       if (calling_scope) {
+               if (!EG(caller_scope) || !EX(object) ||
+                   !instanceof_function(EG(caller_scope), calling_scope 
TSRMLS_CC)) {
+                       EG(caller_scope) = calling_scope;
+               }
+       } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) 
{
+               EG(caller_scope) = NULL;
+       }
+           
        if (fci->object_pp) {
                if ((EX(function_state).function->common.fn_flags & 
ZEND_ACC_STATIC)) {
                        EG(This) = NULL;
@@ -1110,6 +1134,7 @@ int zend_call_function(zend_fcall_info *
        if (EG(This)) {
                zval_ptr_dtor(&EG(This));
        }
+       EG(caller_scope) = current_caller_scope;
        EG(scope) = current_scope;
        EG(This) = current_this;
        EG(current_execute_data) = EX(prev_execute_data);
@@ -1680,6 +1705,11 @@ check_fetch_type:
                                zend_error(E_ERROR, "Cannot access parent:: 
when current class scope has no parent");
                        }
                        return EG(scope)->parent;
+               case ZEND_FETCH_CLASS_STATIC:
+                       if (!EG(caller_scope)) {
+                               zend_error(E_ERROR, "Cannot access static:: 
when no class scope is active");
+                       }
+                       return EG(caller_scope);
                case ZEND_FETCH_CLASS_AUTO: {
                                if (do_normalize) {
                                        lcname = zend_u_str_case_fold(type, 
class_name, class_name_len, 1, &class_name_len);
Index: Zend/zend_globals.h
===================================================================
RCS file: /repository/ZendEngine2/zend_globals.h,v
retrieving revision 1.168
diff -u -p -d -r1.168 zend_globals.h
--- Zend/zend_globals.h 12 Jul 2007 09:23:48 -0000      1.168
+++ Zend/zend_globals.h 10 Sep 2007 07:59:36 -0000
@@ -185,6 +185,7 @@ struct _zend_executor_globals {
        HashTable *zend_constants;      /* constants table */
 
        zend_class_entry *scope;
+       zend_class_entry *caller_scope; /* Scope of the calling class */
 
        zval *This;
 
Index: Zend/zend_language_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_language_parser.y,v
retrieving revision 1.189
diff -u -p -d -r1.189 zend_language_parser.y
--- Zend/zend_language_parser.y 24 Aug 2007 13:50:52 -0000      1.189
+++ Zend/zend_language_parser.y 10 Sep 2007 07:59:36 -0000
@@ -670,6 +670,7 @@ function_call:
 
 fully_qualified_class_name:
                T_STRING { $$ = $1; }
+       |       T_STATIC { $$.op_type = IS_CONST; 
ZVAL_ASCII_STRINGL(&$$.u.constant, "static", sizeof("static")-1, 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); }
 ;
Index: Zend/zend_ptr_stack.h
===================================================================
RCS file: /repository/ZendEngine2/zend_ptr_stack.h,v
retrieving revision 1.26
diff -u -p -d -r1.26 zend_ptr_stack.h
--- Zend/zend_ptr_stack.h       1 Jan 2007 09:29:21 -0000       1.26
+++ Zend/zend_ptr_stack.h       10 Sep 2007 07:59:36 -0000
@@ -52,9 +52,9 @@ END_EXTERN_C()
 
 /*     Not doing this with a macro because of the loop unrolling in the 
element assignment.
        Just using a macro for 3 in the body for readability sake. */
-static inline void zend_ptr_stack_3_push(zend_ptr_stack *stack, void *a, void 
*b, void *c)
+static inline void zend_ptr_stack_4_push(zend_ptr_stack *stack, void *a, void 
*b, void *c, void *d)
 {
-#define ZEND_PTR_STACK_NUM_ARGS 3
+#define ZEND_PTR_STACK_NUM_ARGS 4
 
        ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, ZEND_PTR_STACK_NUM_ARGS)
 
@@ -62,6 +62,7 @@ static inline void zend_ptr_stack_3_push
        *(stack->top_element++) = a;
        *(stack->top_element++) = b;
        *(stack->top_element++) = c;
+       *(stack->top_element++) = d;
 
 #undef ZEND_PTR_STACK_NUM_ARGS
 }
Index: Zend/zend_vm_def.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.181
diff -u -p -d -r1.181 zend_vm_def.h
--- Zend/zend_vm_def.h  7 Sep 2007 09:31:26 -0000       1.181
+++ Zend/zend_vm_def.h  10 Sep 2007 07:59:36 -0000
@@ -1736,7 +1736,7 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CA
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
 
@@ -1763,6 +1763,8 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CA
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -1789,7 +1791,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_ME
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (OP1_TYPE == IS_CONST && OP2_TYPE == IS_CONST) {
                /* try a function in namespace */
@@ -1850,6 +1852,13 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_ME
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;  
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -1864,6 +1873,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_ME
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -1879,7 +1889,7 @@ ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_N
        unsigned int function_name_strlen, lcname_len;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (OP2_TYPE == IS_CONST) {
                function_name = &opline->op2.u.constant;
@@ -1957,6 +1967,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
        zend_op *opline = EX(opline);
        zval **original_return_value;
        zend_class_entry *current_scope = NULL;
+       zend_class_entry *current_caller_scope;
        zval *current_this = NULL;
        int return_value_used = RETURN_VALUE_USED(opline);
        zend_bool should_change_scope;
@@ -1993,6 +2004,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
 
        EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
 
+       current_caller_scope = EG(caller_scope);
        if (EX(function_state).function->common.scope) {
                if (!EG(This) && !(EX(function_state).function->common.fn_flags 
& ZEND_ACC_STATIC)) {
                        int severity;
@@ -2007,7 +2019,11 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
                        /* FIXME: output identifiers properly */
                        zend_error(severity, "Non-static method %v::%v() %s be 
called statically", EX(function_state).function->common.scope->name, 
EX(function_state).function->common.function_name, severity_word);
                }
+               EG(caller_scope) = EX(caller_scope);
+       } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) 
{
+               EG(caller_scope) = NULL;
        }
+
        if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
                unsigned char return_reference = 
EX(function_state).function->common.return_reference;
 
@@ -2128,11 +2144,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
                }
        }
 
+       EG(caller_scope) = current_caller_scope;
        if (should_change_scope) {
                EG(This) = current_this;
                EG(scope) = current_scope;
        }
-       zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), 
(void**)&EX(fbc));
+       zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(caller_scope), 
(void**)&EX(object), (void**)&EX(fbc));
 
        EX(function_state).function = (zend_function *) EX(op_array);
        EG(function_state_ptr) = &EX(function_state);
@@ -2160,7 +2177,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST
        zend_free_op free_op1;
        zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R);
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), 
Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) 
&EX(function_state).function)==FAILURE) {
                /* FIXME: output identifiers properly */
@@ -2631,11 +2648,12 @@ ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY)
                EX_T(opline->result.u.var).var.ptr_ptr = 
&EX_T(opline->result.u.var).var.ptr;
                EX_T(opline->result.u.var).var.ptr = object_zval;
 
-               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), 
EX(object), opline);
+               zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), 
EX(object), EX(caller_scope), opline);
 
                /* We are not handling overloaded classes right now */
                EX(object) = object_zval;
                EX(fbc) = constructor;
+               EX(caller_scope) = EX_T(opline->op1.u.var).class_entry;
 
                ZEND_VM_NEXT_OPCODE();
        }
@@ -4032,7 +4050,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTI
                        }
                        zval_ptr_dtor(&EX(object));
                }
-               zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), 
(void**)&EX(fbc));
+               zend_ptr_stack_3_pop(&EG(arg_types_stack), 
(void*)&EX(caller_scope), (void**)&EX(object), (void**)&EX(fbc));
        }
 
        for (i=0; i<EX(op_array)->last_brk_cont; i++) {
Index: Zend/zend_vm_execute.h
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.h,v
retrieving revision 1.185
diff -u -p -d -r1.185 zend_vm_execute.h
--- Zend/zend_vm_execute.h      7 Sep 2007 09:31:26 -0000       1.185
+++ Zend/zend_vm_execute.h      10 Sep 2007 07:59:36 -0000
@@ -42,6 +42,7 @@ ZEND_API void execute(zend_op_array *op_
 
        /* Initialize execute_data */
        EX(fbc) = NULL;
+       EX(caller_scope) = NULL;
        EX(object) = NULL;
        EX(old_error_reporting) = NULL;
        if (op_array->T < TEMP_VAR_STACK_LIMIT) {
@@ -134,6 +135,7 @@ static int zend_do_fcall_common_helper_S
        zend_op *opline = EX(opline);
        zval **original_return_value;
        zend_class_entry *current_scope = NULL;
+       zend_class_entry *current_caller_scope;
        zval *current_this = NULL;
        int return_value_used = RETURN_VALUE_USED(opline);
        zend_bool should_change_scope;
@@ -170,6 +172,7 @@ static int zend_do_fcall_common_helper_S
 
        EX_T(opline->result.u.var).var.fcall_returned_reference = 0;
 
+       current_caller_scope = EG(caller_scope);
        if (EX(function_state).function->common.scope) {
                if (!EG(This) && !(EX(function_state).function->common.fn_flags 
& ZEND_ACC_STATIC)) {
                        int severity;
@@ -184,7 +187,11 @@ static int zend_do_fcall_common_helper_S
                        /* FIXME: output identifiers properly */
                        zend_error(severity, "Non-static method %v::%v() %s be 
called statically", EX(function_state).function->common.scope->name, 
EX(function_state).function->common.function_name, severity_word);
                }
+               EG(caller_scope) = EX(caller_scope);
+       } else if (EX(function_state).function->type != ZEND_INTERNAL_FUNCTION) 
{
+               EG(caller_scope) = NULL;
        }
+
        if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
                unsigned char return_reference = 
EX(function_state).function->common.return_reference;
 
@@ -305,11 +312,12 @@ static int zend_do_fcall_common_helper_S
                }
        }
 
+       EG(caller_scope) = current_caller_scope;
        if (should_change_scope) {
                EG(This) = current_this;
                EG(scope) = current_scope;
        }
-       zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), 
(void**)&EX(fbc));
+       zend_ptr_stack_3_pop(&EG(arg_types_stack), (void*)&EX(caller_scope), 
(void**)&EX(object), (void**)&EX(fbc));
 
        EX(function_state).function = (zend_function *) EX(op_array);
        EG(function_state_ptr) = &EX(function_state);
@@ -431,11 +439,12 @@ static int ZEND_NEW_SPEC_HANDLER(ZEND_OP
                EX_T(opline->result.u.var).var.ptr_ptr = 
&EX_T(opline->result.u.var).var.ptr;
                EX_T(opline->result.u.var).var.ptr = object_zval;
 
-               zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), 
EX(object), opline);
+               zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), 
EX(object), EX(caller_scope), opline);
 
                /* We are not handling overloaded classes right now */
                EX(object) = object_zval;
                EX(fbc) = constructor;
+               EX(caller_scope) = EX_T(opline->op1.u.var).class_entry;
 
                ZEND_VM_NEXT_OPCODE();
        }
@@ -572,7 +581,7 @@ static int ZEND_HANDLE_EXCEPTION_SPEC_HA
                        }
                        zval_ptr_dtor(&EX(object));
                }
-               zend_ptr_stack_2_pop(&EG(arg_types_stack), (void**)&EX(object), 
(void**)&EX(fbc));
+               zend_ptr_stack_3_pop(&EG(arg_types_stack), 
(void*)&EX(caller_scope), (void**)&EX(object), (void**)&EX(fbc));
        }
 
        for (i=0; i<EX(op_array)->last_brk_cont; i++) {
@@ -676,7 +685,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_
        unsigned int function_name_strlen, lcname_len;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST) {
                function_name = &opline->op2.u.constant;
@@ -874,7 +883,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_
        unsigned int function_name_strlen, lcname_len;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_TMP_VAR == IS_CONST) {
                function_name = &opline->op2.u.constant;
@@ -987,7 +996,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_
        unsigned int function_name_strlen, lcname_len;
        zend_free_op free_op2;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST) {
                function_name = &opline->op2.u.constant;
@@ -1129,7 +1138,7 @@ static int ZEND_INIT_FCALL_BY_NAME_SPEC_
        unsigned int function_name_strlen, lcname_len;
 
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CV == IS_CONST) {
                function_name = &opline->op2.u.constant;
@@ -1501,7 +1510,7 @@ static int ZEND_DO_FCALL_SPEC_CONST_HAND
 
        zval *fname = &opline->op1.u.constant;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (zend_u_hash_find(EG(function_table), Z_TYPE_P(fname), 
Z_UNIVAL_P(fname), Z_UNILEN_P(fname)+1, (void **) 
&EX(function_state).function)==FAILURE) {
                /* FIXME: output identifiers properly */
@@ -2541,7 +2550,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST && IS_CONST == IS_CONST) {
                /* try a function in namespace */
@@ -2602,6 +2611,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -2616,6 +2632,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3086,7 +3103,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST && IS_TMP_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -3147,6 +3164,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3161,6 +3185,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3533,7 +3558,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST && IS_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -3594,6 +3619,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3608,6 +3640,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -3746,7 +3779,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST && IS_UNUSED == IS_CONST) {
                /* try a function in namespace */
@@ -3807,6 +3840,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -3821,6 +3861,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -4161,7 +4202,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_CONST == IS_CONST && IS_CV == IS_CONST) {
                /* try a function in namespace */
@@ -4222,6 +4263,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -4236,6 +4284,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -5760,7 +5809,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = &opline->op2.u.constant;
 
@@ -5787,6 +5836,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6209,7 +6260,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -6236,6 +6287,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -6660,7 +6713,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -6687,6 +6740,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -7204,7 +7259,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R 
TSRMLS_CC);
 
@@ -7231,6 +7286,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_TM
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -9956,7 +10013,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = &opline->op2.u.constant;
 
@@ -9983,6 +10040,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -10008,7 +10067,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST && IS_CONST == IS_CONST) {
                /* try a function in namespace */
@@ -10069,6 +10128,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -10083,6 +10149,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -11647,7 +11714,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -11674,6 +11741,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -11700,7 +11769,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST && IS_TMP_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -11761,6 +11830,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -11775,6 +11851,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -13317,7 +13394,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -13344,6 +13421,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -13370,7 +13449,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST && IS_VAR == IS_CONST) {
                /* try a function in namespace */
@@ -13431,6 +13510,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -13445,6 +13531,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -14238,7 +14325,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST && IS_UNUSED == IS_CONST) {
                /* try a function in namespace */
@@ -14299,6 +14386,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -14313,6 +14407,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -15506,7 +15601,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R 
TSRMLS_CC);
 
@@ -15533,6 +15628,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_VA
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -15558,7 +15655,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
        zval *function_name;
        zend_class_entry *ce;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        if (IS_VAR == IS_CONST && IS_CV == IS_CONST) {
                /* try a function in namespace */
@@ -15619,6 +15716,13 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                EX(fbc) = ce->constructor;
        }
 
+       if (EG(caller_scope) &&
+           instanceof_function(EG(caller_scope), ce TSRMLS_CC)) {
+               EX(caller_scope) = EG(caller_scope);
+       } else {
+               EX(caller_scope) = ce;
+       }
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -15633,6 +15737,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
                }
                if ((EX(object) = EG(This))) {
                        EX(object)->refcount++;
+                       EX(caller_scope) = Z_OBJCE_P(EX(object));
                }
        }
 
@@ -16805,7 +16910,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = &opline->op2.u.constant;
 
@@ -16832,6 +16937,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -17882,7 +17989,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -17909,6 +18016,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -18899,7 +19008,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -18926,6 +19035,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -20181,7 +20292,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R 
TSRMLS_CC);
 
@@ -20208,6 +20319,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_UN
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -22951,7 +23064,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = &opline->op2.u.constant;
 
@@ -22978,6 +23091,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -24486,7 +24601,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -24513,6 +24628,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -26060,7 +26177,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 
TSRMLS_CC);
 
@@ -26087,6 +26204,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
@@ -28065,7 +28184,7 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
        /* FIXME: type is default */
        zend_uchar type = UG(unicode)?IS_UNICODE:IS_STRING;
 
-       zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), NULL);
+       zend_ptr_stack_4_push(&EG(arg_types_stack), EX(fbc), EX(object), 
EX(caller_scope), NULL);
 
        function_name = _get_zval_ptr_cv(&opline->op2, EX(Ts), BP_VAR_R 
TSRMLS_CC);
 
@@ -28092,6 +28211,8 @@ static int ZEND_INIT_METHOD_CALL_SPEC_CV
                zend_error_noreturn(E_ERROR, "Call to a member function %R() on 
a non-object", Z_TYPE_P(function_name), function_name_strval);
        }
 
+       EX(caller_scope) = Z_OBJCE_P(EX(object));
+
        if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
Index: Zend/zend_vm_execute.skl
===================================================================
RCS file: /repository/ZendEngine2/zend_vm_execute.skl,v
retrieving revision 1.7
diff -u -p -d -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    10 Sep 2007 07:59:36 -0000
@@ -13,6 +13,7 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
 
        /* Initialize execute_data */
        EX(fbc) = NULL;
+       EX(caller_scope) = NULL;
        EX(object) = NULL;
        EX(old_error_reporting) = NULL;
        if (op_array->T < TEMP_VAR_STACK_LIMIT) {

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to