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: [email protected]
> 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
>
>
Index: Zend/zend_API.c
===================================================================
RCS file: /repository/ZendEngine2/zend_API.c,v
retrieving revision 1.442
diff -u -p -d -r1.442 zend_API.c
--- Zend/zend_API.c 20 Aug 2007 09:48:41 -0000 1.442
+++ Zend/zend_API.c 24 Aug 2007 16:50:13 -0000
@@ -2836,6 +2836,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.349
diff -u -p -d -r1.349 zend_builtin_functions.c
--- Zend/zend_builtin_functions.c 24 Aug 2007 13:50:52 -0000 1.349
+++ Zend/zend_builtin_functions.c 24 Aug 2007 16:50:13 -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.765
diff -u -p -d -r1.765 zend_compile.c
--- Zend/zend_compile.c 24 Aug 2007 13:50:52 -0000 1.765
+++ Zend/zend_compile.c 24 Aug 2007 16:50:13 -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];
@@ -4868,6 +4875,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 24 Aug 2007 16:50:14 -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.98
diff -u -p -d -r1.98 zend_constants.c
--- Zend/zend_constants.c 24 Aug 2007 13:50:52 -0000 1.98
+++ Zend/zend_constants.c 24 Aug 2007 16:50:14 -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.413
diff -u -p -d -r1.413 zend_execute_API.c
--- Zend/zend_execute_API.c 24 Aug 2007 13:50:52 -0000 1.413
+++ Zend/zend_execute_API.c 24 Aug 2007 16:50:14 -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 24 Aug 2007 16:50:14 -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 24 Aug 2007 16:50:14 -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 24 Aug 2007 16:50:14 -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.179
diff -u -p -d -r1.179 zend_vm_def.h
--- Zend/zend_vm_def.h 24 Aug 2007 13:50:52 -0000 1.179
+++ Zend/zend_vm_def.h 24 Aug 2007 16:50:15 -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 */
@@ -1848,6 +1850,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 {
@@ -1862,6 +1871,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));
}
}
@@ -1877,7 +1887,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;
@@ -1955,6 +1965,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;
@@ -1991,6 +2002,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;
@@ -2005,7 +2017,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;
@@ -2126,11 +2142,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);
@@ -2158,7 +2175,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 */
@@ -2629,11 +2646,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();
}
@@ -4030,7 +4048,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.183
diff -u -p -d -r1.183 zend_vm_execute.h
--- Zend/zend_vm_execute.h 24 Aug 2007 13:50:52 -0000 1.183
+++ Zend/zend_vm_execute.h 24 Aug 2007 16:50:17 -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 */
@@ -2600,6 +2609,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 {
@@ -2614,6 +2630,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -3084,7 +3101,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 */
@@ -3143,6 +3160,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 {
@@ -3157,6 +3181,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -3529,7 +3554,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 */
@@ -3588,6 +3613,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 {
@@ -3602,6 +3634,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -3740,7 +3773,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 */
@@ -3799,6 +3832,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 {
@@ -3813,6 +3853,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -4153,7 +4194,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 */
@@ -4212,6 +4253,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 {
@@ -4226,6 +4274,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -5750,7 +5799,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;
@@ -5777,6 +5826,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 {
@@ -6199,7 +6250,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);
@@ -6226,6 +6277,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 {
@@ -6650,7 +6703,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);
@@ -6677,6 +6730,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 {
@@ -7194,7 +7249,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);
@@ -7221,6 +7276,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 {
@@ -9946,7 +10003,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;
@@ -9973,6 +10030,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 {
@@ -9998,7 +10057,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 */
@@ -10057,6 +10116,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 {
@@ -10071,6 +10137,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -11635,7 +11702,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);
@@ -11662,6 +11729,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 {
@@ -11688,7 +11757,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 */
@@ -11747,6 +11816,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 {
@@ -11761,6 +11837,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -13303,7 +13380,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);
@@ -13330,6 +13407,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 {
@@ -13356,7 +13435,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 */
@@ -13415,6 +13494,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 {
@@ -13429,6 +13515,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -14222,7 +14309,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 */
@@ -14281,6 +14368,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 {
@@ -14295,6 +14389,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -15488,7 +15583,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);
@@ -15515,6 +15610,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 {
@@ -15540,7 +15637,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 */
@@ -15599,6 +15696,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 {
@@ -15613,6 +15717,7 @@ static int ZEND_INIT_STATIC_METHOD_CALL_
}
if ((EX(object) = EG(This))) {
EX(object)->refcount++;
+ EX(caller_scope) = Z_OBJCE_P(EX(object));
}
}
@@ -16785,7 +16890,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;
@@ -16812,6 +16917,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 {
@@ -17862,7 +17969,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);
@@ -17889,6 +17996,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 {
@@ -18879,7 +18988,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);
@@ -18906,6 +19015,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 {
@@ -20161,7 +20272,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);
@@ -20188,6 +20299,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 {
@@ -22931,7 +23044,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;
@@ -22958,6 +23071,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 {
@@ -24466,7 +24581,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);
@@ -24493,6 +24608,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 {
@@ -26040,7 +26157,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);
@@ -26067,6 +26184,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 {
@@ -28045,7 +28164,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);
@@ -28072,6 +28191,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 24 Aug 2007 16:50:17 -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