Index: configure.in =================================================================== RCS file: /repository/php-src/configure.in,v retrieving revision 1.630 diff -u -r1.630 configure.in --- configure.in 29 Jun 2007 01:09:53 -0000 1.630 +++ configure.in 3 Jul 2007 01:38:06 -0000 @@ -1251,7 +1251,8 @@ zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_ts_hash.c zend_stream.c \ - zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_strtol.c) + zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_strtol.c \ + zend_ptr_stack_stack.c ) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c \ Index: tests/classes/late_static_binding_001.phpt =================================================================== RCS file: tests/classes/late_static_binding_001.phpt diff -N tests/classes/late_static_binding_001.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/late_static_binding_001.phpt 3 Jul 2007 01:38:08 -0000 @@ -0,0 +1,61 @@ +--TEST-- +ZE2 Late Static Binding in a static function +--FILE-- + +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== Index: tests/classes/late_static_binding_002.phpt =================================================================== RCS file: tests/classes/late_static_binding_002.phpt diff -N tests/classes/late_static_binding_002.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/late_static_binding_002.phpt 3 Jul 2007 01:38:08 -0000 @@ -0,0 +1,65 @@ +--TEST-- +ZE2 Late Static Binding with instances +--FILE-- +testStaticVar() . "\n"; +echo $testClass->testClassConst() . "\n"; +echo $testClass->testStaticFunction() . "\n"; + +echo $childClass1->testStaticVar() . "\n"; +echo $childClass1->testClassConst() . "\n"; +echo $childClass1->testStaticFunction() . "\n"; + +echo $childClass2->testStaticVar() . "\n"; +echo $childClass2->testClassConst() . "\n"; +echo $childClass2->testStaticFunction() . "\n"; +?> +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== Index: tests/classes/late_static_binding_003.phpt =================================================================== RCS file: tests/classes/late_static_binding_003.phpt diff -N tests/classes/late_static_binding_003.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/late_static_binding_003.phpt 3 Jul 2007 01:38:08 -0000 @@ -0,0 +1,68 @@ +--TEST-- +ZE2 Late Static Binding with dynamic method names +--FILE-- +$func1() . "\n"; +echo $testClass->$func2() . "\n"; +echo $testClass->$func3() . "\n"; + +echo $childClass1->$func1() . "\n"; +echo $childClass1->$func2() . "\n"; +echo $childClass1->$func3() . "\n"; + +echo $childClass2->$func1() . "\n"; +echo $childClass2->$func2() . "\n"; +echo $childClass2->$func3() . "\n"; +?> +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== Index: tests/classes/late_static_binding_004.phpt =================================================================== RCS file: tests/classes/late_static_binding_004.phpt diff -N tests/classes/late_static_binding_004.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/late_static_binding_004.phpt 3 Jul 2007 01:38:08 -0000 @@ -0,0 +1,95 @@ +--TEST-- +ZE2 Late Static Binding with dynamic function calls +--FILE-- + +==DONE== +--EXPECTF-- +TestClassStatic +TestClassConst +TestClassFunction +TestClassStatic +TestClassConst +TestClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +ChildClassStatic +ChildClassConst +ChildClassFunction +TestClassStatic +TestClassConst +TestClassFunction +TestClassStatic +TestClassConst +TestClassFunction +==DONE== Index: tests/classes/late_static_binding_005.phpt =================================================================== RCS file: tests/classes/late_static_binding_005.phpt diff -N tests/classes/late_static_binding_005.phpt --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/classes/late_static_binding_005.phpt 3 Jul 2007 01:38:08 -0000 @@ -0,0 +1,92 @@ +--TEST-- +ZE2 Late Static Binding with exceptions +--FILE-- + +==DONE== +--EXPECTF-- +via A: +A +A +A +A +A +A +A +A +A +via B: +B +B +B +B +B +B +B +B +B +==DONE== Index: Zend/Makefile.am =================================================================== RCS file: /repository/ZendEngine2/Makefile.am,v retrieving revision 1.61 diff -u -r1.61 Makefile.am --- Zend/Makefile.am 5 Dec 2006 08:08:33 -0000 1.61 +++ Zend/Makefile.am 3 Jul 2007 01:38:27 -0000 @@ -15,7 +15,7 @@ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_objects.c zend_object_handlers.c \ zend_objects_API.c zend_ts_hash.c zend_stream.c \ - zend_default_classes.c \ + zend_default_classes.c zend_ptr_stack_stack.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ zend_strtod.c zend_strtod.c zend_strtol.c Index: Zend/zend_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_API.c,v retrieving revision 1.434 diff -u -r1.434 zend_API.c --- Zend/zend_API.c 28 May 2007 20:26:52 -0000 1.434 +++ Zend/zend_API.c 3 Jul 2007 01:38:34 -0000 @@ -2561,7 +2561,11 @@ } } if (colon.v != NULL) { + zend_class_entry *last_scope = EG(scope); + EG(scope) = ce_org; *ce_ptr = zend_u_fetch_class(Z_TYPE_P(callable), Z_UNIVAL_P(callable), clen, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); + EG(scope) = last_scope; + if (!*ce_ptr) { return 0; } Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.752 diff -u -r1.752 zend_compile.c --- Zend/zend_compile.c 28 Jun 2007 20:27:35 -0000 1.752 +++ Zend/zend_compile.c 3 Jul 2007 01:38:43 -0000 @@ -1545,6 +1545,7 @@ fetch_type = zend_get_class_fetch_type(Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant), Z_UNILEN(class_name->u.constant)); switch (fetch_type) { case ZEND_FETCH_CLASS_SELF: + case ZEND_FETCH_CLASS_LATE: case ZEND_FETCH_CLASS_PARENT: SET_UNUSED(opline->op2); opline->extended_value = fetch_type; @@ -2950,7 +2951,9 @@ if ((lcname_len == sizeof("self")-1 && ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "self", sizeof("self")-1)) || (lcname_len == sizeof("parent")-1 && - ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "parent", sizeof("parent")-1))) { + ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "parent", sizeof("parent")-1)) || + (lcname_len == sizeof("static")-1 && + ZEND_U_EQUAL(Z_TYPE(class_name->u.constant), lcname, lcname_len, "static", sizeof("static")-1))) { efree(lcname.v); zend_error(E_COMPILE_ERROR, "Cannot use '%R' as class name as it is reserved", Z_TYPE(class_name->u.constant), Z_UNIVAL(class_name->u.constant)); } @@ -2967,6 +2970,9 @@ if (parent_class_name && parent_class_name->op_type != IS_UNUSED) { switch (parent_class_name->u.EA.type) { + case ZEND_FETCH_CLASS_LATE: + zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved"); + break; case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved"); break; @@ -3077,6 +3083,9 @@ zend_op *opline; switch (interface_znode->u.EA.type) { + case ZEND_FETCH_CLASS_LATE: + zend_error(E_COMPILE_ERROR, "Cannot use 'static' as interface name as it is reserved"); + break; case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as interface name as it is reserved"); break; @@ -4512,6 +4521,9 @@ if ((class_name_len == sizeof("self")-1) && ZEND_U_EQUAL(type, class_name, class_name_len, "self", sizeof("self")-1)) { return ZEND_FETCH_CLASS_SELF; + } else if ((class_name_len == sizeof("static")-1) && + ZEND_U_EQUAL(type, class_name, class_name_len, "static", sizeof("static")-1)) { + return ZEND_FETCH_CLASS_LATE; } else if ((class_name_len == sizeof("parent")-1) && ZEND_U_EQUAL(type, class_name, class_name_len, "parent", sizeof("parent")-1)) { return ZEND_FETCH_CLASS_PARENT; Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.359 diff -u -r1.359 zend_compile.h --- Zend/zend_compile.h 28 Jun 2007 20:19:58 -0000 1.359 +++ Zend/zend_compile.h 3 Jul 2007 01:38:44 -0000 @@ -626,6 +626,7 @@ #define ZEND_FETCH_CLASS_GLOBAL 4 #define ZEND_FETCH_CLASS_AUTO 5 #define ZEND_FETCH_CLASS_INTERFACE 6 +#define ZEND_FETCH_CLASS_LATE 7 #define ZEND_FETCH_CLASS_FLAGS 0xF0 #define ZEND_FETCH_CLASS_NO_NORMALIZE 0x10 #define ZEND_FETCH_CLASS_NO_AUTOLOAD 0x80 Index: Zend/zend_exceptions.c =================================================================== RCS file: /repository/ZendEngine2/zend_exceptions.c,v retrieving revision 1.114 diff -u -r1.114 zend_exceptions.c --- Zend/zend_exceptions.c 30 May 2007 16:31:47 -0000 1.114 +++ Zend/zend_exceptions.c 3 Jul 2007 01:38:45 -0000 @@ -55,6 +55,10 @@ /* no need to rethrow the exception */ return; } + if (exception != NULL) { + /* somehow its required */ + zend_ptr_stack_stack_pop(&EG(class_call_stack_stack)); + } EG(opline_before_exception) = EG(current_execute_data)->opline; EG(current_execute_data)->opline = &EG(active_op_array)->opcodes[EG(active_op_array)->last-1-1]; } Index: Zend/zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.405 diff -u -r1.405 zend_execute_API.c --- Zend/zend_execute_API.c 27 Jun 2007 11:16:21 -0000 1.405 +++ Zend/zend_execute_API.c 3 Jul 2007 01:38:47 -0000 @@ -158,6 +158,9 @@ EG(in_autoload) = NULL; EG(autoload_func) = NULL; + EG(last_fetched_class) = NULL; + zend_ptr_stack_stack_init(&EG(class_call_stack_stack)); + zend_ptr_stack_init(&EG(argument_stack)); zend_ptr_stack_push(&EG(argument_stack), (void *) NULL); @@ -303,6 +306,7 @@ zend_hash_apply(EG(class_table), (apply_func_t) zend_cleanup_class_data TSRMLS_CC); zend_ptr_stack_destroy(&EG(argument_stack)); + zend_ptr_stack_stack_destroy(&EG(class_call_stack_stack)); /* Destroy all op arrays */ if (EG(full_tables_cleanup)) { @@ -757,6 +761,7 @@ found = (*ce != NULL?SUCCESS:FAILURE); fci->object_pp = EG(This)?&EG(This):NULL; EX(object) = EG(This); + } else if (EG(active_op_array) && Z_UNILEN_PP(fci->object_pp) == sizeof("parent")-1 && ZEND_U_EQUAL(Z_TYPE_PP(fci->object_pp), Z_UNIVAL_PP(fci->object_pp), Z_UNILEN_PP(fci->object_pp), "parent", sizeof("parent")-1)) { @@ -793,6 +798,7 @@ fci->function_table = &(*ce)->function_table; calling_scope = *ce; + } else { zend_error(E_NOTICE, "Non-callable array passed to zend_call_function()"); return FAILURE; @@ -1009,6 +1015,8 @@ current_scope = EG(scope); EG(scope) = calling_scope; + EG(last_fetched_class) = calling_scope; + current_this = EG(This); if (fci->object_pp) { @@ -1060,7 +1068,13 @@ EG(return_value_ptr_ptr) = fci->retval_ptr_ptr; EG(active_op_array) = (zend_op_array *) EX(function_state).function; original_opline_ptr = EG(opline_ptr); + + zend_ptr_stack_stack_push(&EG(class_call_stack_stack), calling_scope); + zend_execute(EG(active_op_array) TSRMLS_CC); + + zend_ptr_stack_stack_pop(&EG(class_call_stack_stack)); + if (!fci->symbol_table) { zend_hash_destroy(EG(active_symbol_table)); FREE_HASHTABLE(EG(active_symbol_table)); @@ -1627,10 +1641,35 @@ check_fetch_type: switch (fetch_type) { + case ZEND_FETCH_CLASS_LATE: + if (!EG(scope)) { + zend_error(E_ERROR, "Cannot access static:: when no class scope is active"); + } + zend_class_entry *last_scope = EG(scope); + + /* The late binding scope has to be found on the top-most call + * stack of the stack */ + zend_ptr_stack *last_stack = EG(class_call_stack_stack).elements[EG(class_call_stack_stack).top-1]; + + int i = last_stack->top; + while (--i >= 0) { + /* check the relationship between the scopes */ + zend_bool result1 = instanceof_function(EG(scope), last_stack->elements[i]); + zend_bool result2 = instanceof_function(last_stack->elements[i], EG(scope)); + if(result1 != 1 && result2 != 1) { + break; + } else { + last_scope = last_stack->elements[i]; + } + } + + EG(last_fetched_class) = last_scope; + return last_scope; case ZEND_FETCH_CLASS_SELF: if (!EG(scope)) { zend_error(E_ERROR, "Cannot access self:: when no class scope is active"); } + EG(last_fetched_class) = EG(scope); return EG(scope); case ZEND_FETCH_CLASS_PARENT: if (!EG(scope)) { @@ -1639,6 +1678,7 @@ if (!EG(scope)->parent) { zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent"); } + EG(last_fetched_class) = EG(scope)->parent; return EG(scope)->parent; case ZEND_FETCH_CLASS_AUTO: { if (do_normalize) { @@ -1672,6 +1712,9 @@ if (lcname.v != class_name.v) { efree(lcname.v); } + + EG(last_fetched_class) = *pce; + return *pce; } } Index: Zend/zend_globals.h =================================================================== RCS file: /repository/ZendEngine2/zend_globals.h,v retrieving revision 1.167 diff -u -r1.167 zend_globals.h --- Zend/zend_globals.h 16 Feb 2007 19:36:45 -0000 1.167 +++ Zend/zend_globals.h 3 Jul 2007 01:38:48 -0000 @@ -29,6 +29,7 @@ #include "zend_stack.h" #include "zend_ptr_stack.h" +#include "zend_ptr_stack_stack.h" #include "zend_hash.h" #include "zend_llist.h" #include "zend_objects.h" @@ -156,6 +157,9 @@ zend_function_state *function_state_ptr; zend_ptr_stack arg_types_stack; + + zend_class_entry *last_fetched_class; + zend_ptr_stack_stack class_call_stack_stack; /* symbol table cache */ HashTable *symtable_cache[SYMTABLE_CACHE_SIZE]; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.184 diff -u -r1.184 zend_language_parser.y --- Zend/zend_language_parser.y 28 Jun 2007 00:01:57 -0000 1.184 +++ Zend/zend_language_parser.y 3 Jul 2007 01:38:54 -0000 @@ -646,10 +646,12 @@ fully_qualified_class_name: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_STATIC { znode tmp; tmp.op_type = IS_CONST; ZVAL_STRING(&tmp.u.constant, "static", 1); INIT_PZVAL(&tmp.u.constant); zend_do_fetch_class(&$$, &tmp TSRMLS_CC); } ; class_name_reference: T_STRING { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | T_STATIC { znode tmp; tmp.op_type = IS_CONST; ZVAL_STRING(&tmp.u.constant, "static", 1); INIT_PZVAL(&tmp.u.constant); zend_do_fetch_class(&$$, &tmp TSRMLS_CC); } | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; Index: Zend/zend_ptr_stack_stack.c =================================================================== RCS file: Zend/zend_ptr_stack_stack.c diff -N Zend/zend_ptr_stack_stack.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/zend_ptr_stack_stack.c 3 Jul 2007 01:39:01 -0000 @@ -0,0 +1,112 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: | + +----------------------------------------------------------------------+ +*/ + +/* $Id:$ */ + +#include "zend.h" +#include "zend_ptr_stack.h" +#include "zend_ptr_stack_stack.h" + +ZEND_API void zend_ptr_stack_stack_init(zend_ptr_stack_stack *stack) +{ + stack->top_stack = stack->elements = (zend_ptr_stack **) emalloc(sizeof(zend_ptr_stack *)*PTR_STACK_STACK_BLOCK_SIZE); + stack->max = PTR_STACK_STACK_BLOCK_SIZE; + stack->top = 0; +} + +ZEND_API void zend_ptr_stack_stack_new(zend_ptr_stack_stack *stack) +{ + zend_ptr_stack *newStack = emalloc(sizeof(zend_ptr_stack)); + zend_ptr_stack_init(newStack); + ZEND_PTR_STACK_STACK_RESIZE_IF_NEEDED(stack, 1) + stack->top++; + *(stack->top_stack++) = newStack; + +} + +ZEND_API void zend_ptr_stack_stack_push(zend_ptr_stack_stack *stack, void *a) +{ + /* push an element on the topmost stack */ + + if (stack->top == 0) { + zend_ptr_stack_stack_new(stack); + } + + zend_ptr_stack_push(stack->elements[stack->top-1], a); +} + +ZEND_API void *zend_ptr_stack_stack_pop(zend_ptr_stack_stack *stack) +{ + /* pop an element off the topmost stack, and eventually + * delete the topmost stack itself, if it's empty*/ + int i = stack->top; + while (--i >= 0) { + zend_ptr_stack *current_stack = stack->elements[i]; + if (current_stack->top == 0) { + /* empty stack, pop it */ + stack->top--; + zend_ptr_stack_destroy(current_stack); + efree(current_stack); + stack->top_stack--; + } else if (current_stack->top == 1) { + /* last element of the stack, pop it */ + zend_ptr_stack *elem = zend_ptr_stack_pop(current_stack); + + stack->top--; + zend_ptr_stack_destroy(current_stack); + efree(current_stack); + stack->top_stack--; + + return elem; + } else { + /* pop that */ + return zend_ptr_stack_pop(current_stack); + } + + } + /* reached the end of the stack, nothing left */ + return NULL; +} + + + +ZEND_API void zend_ptr_stack_stack_destroy(zend_ptr_stack_stack *stack) +{ + int i = stack->top; + while (--i >= 0) { + zend_ptr_stack_destroy(stack->elements[i]); + efree(stack->elements[i]); + } + + if (stack->elements) { + efree(stack->elements); + } +} + +ZEND_API int zend_ptr_stack_stack_num_elements(zend_ptr_stack_stack *stack) +{ + return stack->top; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ Index: Zend/zend_ptr_stack_stack.h =================================================================== RCS file: Zend/zend_ptr_stack_stack.h diff -N Zend/zend_ptr_stack_stack.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ Zend/zend_ptr_stack_stack.h 3 Jul 2007 01:39:01 -0000 @@ -0,0 +1,59 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: | + +----------------------------------------------------------------------+ +*/ + +/* $Id:$ */ + +#ifndef ZEND_PTR_STACK_STACK_H +#define ZEND_PTR_STACK_STACK_H + +typedef struct _zend_ptr_stack_stack { + int top, max; + zend_ptr_stack **elements; + zend_ptr_stack **top_stack; +} zend_ptr_stack_stack; + + +#define PTR_STACK_STACK_BLOCK_SIZE 64 + +BEGIN_EXTERN_C() +ZEND_API void zend_ptr_stack_stack_init(zend_ptr_stack_stack *stack); +ZEND_API void zend_ptr_stack_stack_push(zend_ptr_stack_stack *stack, void *a); +ZEND_API void zend_ptr_stack_stack_new(zend_ptr_stack_stack *stack); +ZEND_API void *zend_ptr_stack_stack_pop(zend_ptr_stack_stack *stack); +ZEND_API void zend_ptr_stack_stack_destroy(zend_ptr_stack_stack *stack); +ZEND_API int zend_ptr_stack_stack_num_elements(zend_ptr_stack_stack *stack); +END_EXTERN_C() + +#define ZEND_PTR_STACK_STACK_RESIZE_IF_NEEDED(stack, count) \ + if (stack->top+count > stack->max) { \ + /* we need to allocate more memory */ \ + stack->max *= 2; \ + stack->max += count; \ + stack->elements = (zend_ptr_stack **) erealloc(stack->elements, (sizeof(zend_ptr_stack *) * (stack->max))); \ + stack->top_stack = stack->elements+stack->top; \ + } + +#endif /* ZEND_PTR_STACK_STACK_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ Index: Zend/zend_vm_execute.h =================================================================== RCS file: /repository/ZendEngine2/zend_vm_execute.h,v retrieving revision 1.173 diff -u -r1.173 zend_vm_execute.h --- Zend/zend_vm_execute.h 18 Jun 2007 11:20:01 -0000 1.173 +++ Zend/zend_vm_execute.h 3 Jul 2007 01:39:29 -0000 @@ -90,6 +90,9 @@ #endif if (EX(opline)->handler(&execute_data TSRMLS_CC) > 0) { + if (EX(function_state).function->common.scope != NULL) { + zend_ptr_stack_stack_pop(&EG(class_call_stack_stack)); + } return; } @@ -134,6 +137,7 @@ zend_op *opline = EX(opline); zval **original_return_value; zend_class_entry *current_scope = NULL; + zend_class_entry *last_scope = NULL; zval *current_this = NULL; int return_value_used = RETURN_VALUE_USED(opline); zend_bool should_change_scope; @@ -168,6 +172,18 @@ should_change_scope = 0; } + if (EX(function_state).function->common.scope == NULL) { + /* normal function, scope is always broken, push new stack on + * class_call_stack_stack if necessary */ + if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + zend_ptr_stack_stack_new(&EG(class_call_stack_stack)); + zend_ptr_stack_stack_push(&EG(class_call_stack_stack), EG(scope)); + } + } else { + /* we are executing a method, static or not check scope */ + zend_ptr_stack_stack_push(&EG(class_call_stack_stack), EG(last_fetched_class)); + } + EX_T(opline->result.u.var).var.fcall_returned_reference = 0; if (EX(function_state).function->common.scope) { @@ -305,6 +321,7 @@ } } + last_scope = EG(scope); if (should_change_scope) { EG(This) = current_this; EG(scope) = current_scope; @@ -417,6 +434,8 @@ INIT_PZVAL(object_zval); constructor = Z_OBJ_HT_P(object_zval)->get_constructor(object_zval TSRMLS_CC); + + zend_ptr_stack_stack_new(&EG(class_call_stack_stack)); if (constructor == NULL) { if (RETURN_VALUE_USED(opline)) { @@ -6350,6 +6369,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -6894,6 +6916,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -9648,6 +9673,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -11191,6 +11219,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -12774,6 +12805,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -14789,6 +14823,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -16001,6 +16038,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -17064,6 +17104,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -18081,6 +18124,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -19363,6 +19409,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -22135,6 +22184,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -23670,6 +23722,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -25244,6 +25299,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) { @@ -27249,6 +27307,9 @@ zend_error_noreturn(E_ERROR, "Object does not support method calls"); } + if (Z_OBJCE_P(EX(object))) { + EG(last_fetched_class) = Z_OBJCE_P(EX(object)); + } /* First, locate the function. */ EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); if (!EX(fbc)) {