diff options
author | SVN Migration <svn@php.net> | 2002-09-08 15:38:45 +0000 |
---|---|---|
committer | SVN Migration <svn@php.net> | 2002-09-08 15:38:45 +0000 |
commit | e94c67742f6f4bf9fe9a381273d1ea6a16db5ec3 (patch) | |
tree | 7cb16c2c460931bbf4798a79167770dfb48ff643 /Zend | |
parent | 6c22f90b4a3d24a8da83e78f8eef97cba6c05197 (diff) | |
download | php-git-php-4.3.0dev_zend2_alpha3.tar.gz |
This commit was manufactured by cvs2svn to create tagphp-4.3.0dev_zend2_alpha3
'php_4_3_0_dev_zend2_alpha3'.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/ChangeLog | 202 | ||||
-rw-r--r-- | Zend/ZEND_CHANGES | 78 | ||||
-rw-r--r-- | Zend/Zend.m4 | 2 | ||||
-rw-r--r-- | Zend/zend.c | 7 | ||||
-rw-r--r-- | Zend/zend.h | 12 | ||||
-rw-r--r-- | Zend/zend_builtin_functions.c | 143 | ||||
-rw-r--r-- | Zend/zend_compile.c | 19 | ||||
-rw-r--r-- | Zend/zend_compile.h | 7 | ||||
-rw-r--r-- | Zend/zend_execute.c | 64 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 31 | ||||
-rw-r--r-- | Zend/zend_extensions.c | 2 | ||||
-rw-r--r-- | Zend/zend_extensions.h | 2 | ||||
-rw-r--r-- | Zend/zend_hash.c | 2 | ||||
-rw-r--r-- | Zend/zend_ini.c | 32 | ||||
-rw-r--r-- | Zend/zend_llist.c | 2 | ||||
-rw-r--r-- | Zend/zend_object_handlers.c | 275 | ||||
-rw-r--r-- | Zend/zend_objects.c | 2 | ||||
-rw-r--r-- | Zend/zend_operators.c | 12 |
18 files changed, 798 insertions, 96 deletions
diff --git a/Zend/ChangeLog b/Zend/ChangeLog index f9bd40b66e..9e05547d74 100644 --- a/Zend/ChangeLog +++ b/Zend/ChangeLog @@ -1,3 +1,205 @@ +2002-09-05 Stanislav Malyshev <stas@zend.com> + + * zend_compile.c: quick-n-dirty inheritance support for __handlers + +2002-09-04 Sebastian Bergmann <sb@sebastian-bergmann.de> + + * ZEND_CHANGES: Whitespace fixes. + +2002-09-04 Stanislav Malyshev <stas@zend.com> + + * zend_object_handlers.c: remove dead code + + * ZEND_CHANGES + zend_object_handlers.c: Fix __call and add some docs + +2002-09-04 Sebastian Bergmann <sb@sebastian-bergmann.de> + + * zend_object_handlers.c: Fix ZTS build. + + * ZEND_CHANGES: TBD: __call(), __get(), __set(). + +2002-09-04 Stanislav Malyshev <stas@zend.com> + + * zend.h + zend_compile.c + zend_compile.h + zend_execute.c + zend_extensions.h + zend_object_handlers.c + zend_objects.c: Support for __get, __set and __call in classes. + This should work as follows: if class hasn't member with given name, + __get/__set is called. If class has no method with given name, __call is called. + __get/__set are not recursive, __call can be. + +2002-09-04 Sebastian Bergmann <sb@sebastian-bergmann.de> + + * ZEND_CHANGES: Workaround for superfluous comma in var_export() result. + + * ZEND_CHANGES: + Let debug_backtrace() example print out the class name, if applicable, and the function/method arguments. + +2002-09-03 Thies C. Arntzen <thies@thieso.net> + + * zend_builtin_functions.c: nuke warning + + * zend_builtin_functions.c: nuke unneeded stuff + +2002-09-03 Zeev Suraski <zeev@zend.com> + + * zend.c + zend.h + zend_ini.c: MFZE1 + +2002-09-03 Derick Rethans <d.rethans@jdimedia.nl> + + * zend_ini.c: - Revert + + * zend_ini.c: + - MFH for: Apply rest of html errors fix (Patch by Jan Lehnardt <jan@php.net>) + +2002-09-03 Sebastian Bergmann <sb@sebastian-bergmann.de> + + * zend.h: + Add html_errors to zend_utility_values. Patch by Jan Lehnardt <jan@php.net>. + +2002-09-03 Andi Gutmans <andi@zend.com> + + * zend_builtin_functions.c: - Fix typo + +2002-09-02 Thies C. Arntzen <thies@thieso.net> + + * zend_builtin_functions.c: + refine last patch. if the argument-stack is not consistent don't try to show + arguments. no call to zend_error is made as we might end up in an infinite + recursion if called from an error_handler. + so: if the arguments to functions aren't shown in debug_backtrace this is 'cause + the arument stack was not consistent when debug_backtrace was called. + + * zend_builtin_functions.c: + debug_backtrace() now checks the complete argument-stack for consistency. + +2002-09-02 Stanislav Malyshev <stas@zend.com> + + * zend_execute.c: MFZE1 + +2002-09-01 Andi Gutmans <andi@zend.com> + + * zend_llist.c: - Fix leak reported by "l0t3k" <cshmoove@hotmail.com> + +2002-09-01 Stanislav Malyshev <stas@zend.com> + + * zend_operators.c: MFZE1 + +2002-08-28 Thies Arntzen <thies@pb1.pair.com> + + * zend_builtin_functions.c + zend_execute_API.c: debug_backtrace() + - make args passed to functions called vy call_user_function available again. + + * zend_builtin_functions.c: debug_backtrace(): + - make args work if called from the error_handler + - fix refcount for args + + * zend.c: + clear current_execute_data on bailout as it would point into some freed area + on the stack. + +2002-08-28 derick <derick@pb1.pair.com> + + * zend.c: - MFZE1 + +2002-08-26 Thies Arntzen <thies@pb1.pair.com> + + * zend_builtin_functions.c: + debug_backtrace(): show name of included file for include and require calls + plus some small fixes suggested by andi. + +2002-08-24 Andi Gutmans <andi@pb1.pair.com> + + * zend_builtin_functions.c: - Whitespace + + * zend_builtin_functions.c: - Whitespace and better variable name + +2002-08-24 Thies Arntzen <thies@pb1.pair.com> + + * zend_builtin_functions.c: fix warning + +2002-08-23 Andi Gutmans <andi@pb1.pair.com> + + * Zend.m4: - Add \n to configure fprintf + + * zend_extensions.c: - dlerror -> DL_ERROR + +2002-08-23 Thies Arntzen <thies@pb1.pair.com> + + * zend_builtin_functions.c: + debug_backtrace: show include/require/eval as normal functions on the stack + +2002-08-23 derick <derick@pb1.pair.com> + + * zend_builtin_functions.c: - No spaces :) + +2002-08-23 Thies Arntzen <thies@pb1.pair.com> + + * zend_builtin_functions.c: + - debug_backtrace now also returns an array containing the arguments of the + called function. + + zeev, andi - is knowing the structure of the stack considered a bad thing in + zend_builtin_function? if yes i would have to create a new function in + zend_ptr_stack.c (but i think we are save this way) + + * zend_builtin_functions.c + zend_execute_API.c: - debug_backtrace: + added "type" ('->' or '::') for object calls. + made calls done thru call_user_func show-up correct in backtraces. + + andi, + does this look correct to you? + + * zend_execute.c: those are set by RETURN_FROM_EXECUTE + +2002-08-21 Thies Arntzen <thies@pb1.pair.com> + + * zend_execute.c: + zend_execute: make sure that current_execute_data points to the right thing + after coming back from recursion. + +2002-08-19 Zeev Suraski <zeev@pb1.pair.com> + + * zend_operators.c: MFZE1 + +2002-08-17 Andi Gutmans <andi@pb1.pair.com> + + * zend_execute.c: MFZE1 + +2002-08-17 Zeev Suraski <zeev@pb1.pair.com> + + * zend_execute.c + zend_hash.c: MFZE1 + +2002-08-16 Stig Bakken <ssb@pb1.pair.com> + + * zend.c: * append emacs footer + + * zend.c: * remove builtin exception class + +2002-08-16 Andi Gutmans <andi@pb1.pair.com> + + * zend.c: - Fix whitespace + +2002-08-16 Stig Bakken <ssb@pb1.pair.com> + + * zend_execute_API.c + zend_globals.h + zend.c + zend_builtin_functions.c: + - Added set_exception_handler() function for registering a global, + catch-all exception handling function + - Added set_exception_handler() function for registering a global, + catch-all exception handling function (Stig) + 2002-08-15 Zeev Suraski <zeev@pb1.pair.com> * flex.skl diff --git a/Zend/ZEND_CHANGES b/Zend/ZEND_CHANGES index 8b7f465964..817001cc4b 100644 --- a/Zend/ZEND_CHANGES +++ b/Zend/ZEND_CHANGES @@ -483,7 +483,7 @@ Changes in the Zend Engine 2.0 <?php class foo { - static $my_static = 5; + static $my_static = 5; } print foo::$my_static; @@ -510,11 +510,22 @@ Changes in the Zend Engine 2.0 $backtrace = debug_backtrace(); foreach ($backtrace as $step) { - $class = isset($step['class']) ? $step['class'] . '::' : ''; + if (!empty($step['args'])) { + foreach ($step['args'] as $arg) { + $args = isset($args) ? $args . ', ' : ''; + $args .= var_export($arg, true); + } + } else { + $args = ''; + } + + $args = str_replace(array("\n", ',)'), array('', ')'), $args); printf( - "%s [%s:%s]\n", + "%s%s(%s) [%s:%s]\n", + isset($step['class']) ? $step['class'] . '::' : '', $step['function'], + $args, $step['file'], $step['line'] ); @@ -523,6 +534,67 @@ Changes in the Zend Engine 2.0 * __autoload(). TBD. + * Method calls and property accesses can be overloaded + by class methods __call(), __get() and __set(). + + __get() and __set() Example: + + <?php + class Setter { + public $n; + public $x = array('a' => 1, 'b' => 2, 'c' => 3); + + function __get($nm) { + print "Getting [$nm]\n"; + + if(isset($this->x[$nm])) { + $r = $this->x[$nm]; + print "Returning: $r\n"; + return $r; + } else { + print "Nothing!\n"; + } + } + + function __set($nm, $val) { + print "Setting [$nm] to $val\n"; + + if(isset($this->x[$nm])) { + $this->x[$nm] = $val; + print "OK!\n"; + } else { + print "Not OK!\n"; + } + } + } + + $foo = new Setter(); + $foo->n = 1; + $foo->a = 100; + $foo->a++; + $foo->z++; + var_dump($foo); + ?> + + __call() Example: + + <?php + class Caller { + var $x = array(1, 2, 3); + + function __call($m, $a) { + print "Method $m called:\n"; + var_dump($a); + return $this->x; + } + } + + $foo = new Caller(); + $a = $foo->test(1, '2', 3.4, true); + var_dump($a); + ?> + + Changes in the Zend Engine 1.0 The Zend Engine was designed from the ground up for increased speed, diff --git a/Zend/Zend.m4 b/Zend/Zend.m4 index 2f49e45c09..84a80af285 100644 --- a/Zend/Zend.m4 +++ b/Zend/Zend.m4 @@ -209,7 +209,7 @@ int main() } fp = fopen("conftest.zend", "w"); - fprintf(fp, "%d %d", ZEND_MM_ALIGNMENT, zeros); + fprintf(fp, "%d %d\n", ZEND_MM_ALIGNMENT, zeros); fclose(fp); exit(0); diff --git a/Zend/zend.c b/Zend/zend.c index 1940aea4e4..09cf2294da 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -65,7 +65,7 @@ zend_class_entry global_main_class; HashTable *global_auto_globals_table; #endif -zend_utility_values zend_uv; +ZEND_API zend_utility_values zend_uv; ZEND_API zval zval_used_for_init; /* True global variable */ @@ -208,7 +208,7 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int ZEND_PUTS("Array\n"); if (++expr->value.ht->nApplyCount>1) { ZEND_PUTS(" *RECURSION*"); - expr->value.ht->nApplyCount=0; + expr->value.ht->nApplyCount--; return; } print_hash(expr->value.ht, indent); @@ -220,7 +220,7 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int if (++object->properties->nApplyCount>1) { ZEND_PUTS(" *RECURSION*"); - object->properties->nApplyCount=0; + object->properties->nApplyCount--; return; } zend_printf("%s Object\n", object->ce->name); @@ -549,6 +549,7 @@ ZEND_API void _zend_bailout(char *filename, uint lineno) } CG(unclean_shutdown) = 1; CG(in_compilation) = EG(in_execution) = 0; + EG(current_execute_data) = NULL; longjmp(EG(bailout), FAILURE); } END_EXTERN_C() diff --git a/Zend/zend.h b/Zend/zend.h index 94009199ee..393203d7f3 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -22,7 +22,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "2.0.0-alpha2" +#define ZEND_VERSION "2.0.0-alpha3" #define ZEND_ENGINE_2 @@ -226,6 +226,8 @@ typedef struct _zend_class_entry zend_class_entry; typedef struct _zend_object { zend_class_entry *ce; HashTable *properties; + int in_get:1; + int in_set:1; } zend_object; typedef unsigned int zend_object_handle; @@ -311,9 +313,14 @@ struct _zend_class_entry { union _zend_function *constructor; union _zend_function *destructor; union _zend_function *clone; + union _zend_function *__get; + union _zend_function *__set; + union _zend_function *__call; /* handlers */ zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); + + /* old handlers */ void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); zval (*handle_property_get)(zend_property_reference *property_reference); int (*handle_property_set)(zend_property_reference *property_reference, zval *value); @@ -336,6 +343,7 @@ typedef struct _zend_utility_functions { typedef struct _zend_utility_values { char *import_use_extension; uint import_use_extension_length; + zend_bool html_errors; } zend_utility_values; @@ -462,7 +470,7 @@ void zenderror(char *error); /* The following #define is used for code duality in PHP for Engine 1 & 2 */ #define ZEND_STANDARD_CLASS_DEF_PTR zend_standard_class_def extern ZEND_API zend_class_entry *zend_standard_class_def; -extern zend_utility_values zend_uv; +extern ZEND_API zend_utility_values zend_uv; extern ZEND_API zval zval_used_for_init; END_EXTERN_C() diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index f58ab23876..5a49e761f4 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1247,6 +1247,26 @@ ZEND_FUNCTION(get_defined_constants) /* }}} */ +static zval *debug_backtrace_get_args(void ***curpos TSRMLS_DC) { + void **p = *curpos - 2; + zval *arg_array, **arg; + int arg_count = (ulong) *p; + + *curpos -= (arg_count+2); + + MAKE_STD_ZVAL(arg_array); + array_init(arg_array); + p -= arg_count; + + while (--arg_count >= 0) { + arg = (zval **) p++; + SEPARATE_ZVAL_TO_MAKE_IS_REF(arg); + (*arg)->refcount++; + add_next_index_zval(arg_array, *arg); + } + return arg_array; +} + /* {{{ proto void debug_backtrace(void) Prints out a backtrace */ ZEND_FUNCTION(debug_backtrace) @@ -1256,43 +1276,130 @@ ZEND_FUNCTION(debug_backtrace) char *function_name; char *filename; char *class_name; + char *call_type; + char *include_filename = NULL; zval *stack_frame; + void **cur_arg_pos = EG(argument_stack).top_element; + void **args = cur_arg_pos; + int arg_stack_consistent = 0; + + if (ZEND_NUM_ARGS()) { + WRONG_PARAM_COUNT; + } + + while (--args >= EG(argument_stack).elements) { + if (*args--) { + break; + } + args -= *(ulong*)args; + + if (args == EG(argument_stack).elements) { + arg_stack_consistent = 1; + break; + } + } ptr = EG(current_execute_data); - /* Skip debug_backtrace() itself */ + /* skip debug_backtrace() */ ptr = ptr->prev_execute_data; - + cur_arg_pos -= 2; + array_init(return_value); while (ptr) { MAKE_STD_ZVAL(stack_frame); array_init(stack_frame); - class_name = NULL; - - if (ptr->object) { - class_name = Z_OBJCE(*ptr->object)->name; - } - if (ptr->function_state.function->common.scope) { - class_name = ptr->function_state.function->common.scope->name; + if (ptr->op_array) { + filename = ptr->op_array->filename; + lineno = ptr->opline->lineno; + add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1); + add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno); + + /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function + * and debug_baktrace() might have been called by the error_handler. in this case we don't + * want to pop anything of the argument-stack */ + } else { + filename = NULL; } + function_name = ptr->function_state.function->common.function_name; - - filename = ptr->op_array->filename; - lineno = ptr->opline->lineno; if (function_name) { add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1); + + if (ptr->object) { + class_name = Z_OBJCE(*ptr->object)->name; + call_type = "->"; + } else if (ptr->function_state.function->common.scope) { + class_name = ptr->function_state.function->common.scope->name; + call_type = "::"; + } else { + class_name = NULL; + call_type = NULL; + } + + if (class_name) { + add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, 1); + add_assoc_string_ex(stack_frame, "type", sizeof("type"), call_type, 1); + } + + if ((! ptr->opline) || ((ptr->opline->opcode == ZEND_DO_FCALL_BY_NAME) || (ptr->opline->opcode == ZEND_DO_FCALL))) { + if (arg_stack_consistent) { + add_assoc_zval_ex(stack_frame, "args", sizeof("args"), debug_backtrace_get_args(&cur_arg_pos TSRMLS_CC)); + } + } + } else { + /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */ + zend_bool build_filename_arg = 1; + + switch (ptr->opline->op2.u.constant.value.lval) { + case ZEND_EVAL: + function_name = "eval"; + build_filename_arg = 0; + break; + case ZEND_INCLUDE: + function_name = "include"; + break; + case ZEND_REQUIRE: + function_name = "require"; + break; + case ZEND_INCLUDE_ONCE: + function_name = "include_once"; + break; + case ZEND_REQUIRE_ONCE: + function_name = "require_once"; + break; + default: + /* this can actually happen if you use debug_backtrace() in your error_handler and + * you're in the top-scope */ + function_name = "unknown"; + build_filename_arg = 0; + break; + } + + if (build_filename_arg && include_filename) { + zval *arg_array; + + MAKE_STD_ZVAL(arg_array); + array_init(arg_array); + + /* include_filename always points to the last filename of the last last called-fuction. + if we have called include in the frame above - this is the file we have included. + */ + + add_next_index_string(arg_array, include_filename, 1); + add_assoc_zval_ex(stack_frame, "args", sizeof("args"), arg_array); + } + + add_assoc_string_ex(stack_frame, "function", sizeof("function"), function_name, 1); } - if (class_name) { - add_assoc_string_ex(stack_frame, "class", sizeof("class"), class_name, 1); - } - add_assoc_string_ex(stack_frame, "file", sizeof("file"), filename, 1); - add_assoc_long_ex(stack_frame, "line", sizeof("line"), lineno); - /* add_assoc_stringl_ex(stack_frame, "class", sizeof("class")-1, class_name, class_name_length, 1); */ + add_next_index_zval(return_value, stack_frame); + include_filename = filename; + ptr = ptr->prev_execute_data; } } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bb7403b0c2..34d3e87608 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -895,10 +895,6 @@ void zend_do_free(znode *op1 TSRMLS_DC) } } -#define ZEND_CLONE_FUNC_NAME "__clone" -#define ZEND_CONSTRUCTOR_FUNC_NAME "__construct" -#define ZEND_DESTRUCTOR_FUNC_NAME "__destruct" - void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference TSRMLS_DC) { zend_op_array op_array; @@ -938,6 +934,12 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array); } else if ((function_name->u.constant.value.str.len == sizeof(ZEND_CLONE_FUNC_NAME)-1) && (!memcmp(function_name->u.constant.value.str.val, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)))) { CG(active_class_entry)->clone = (zend_function *) CG(active_op_array); + } else if ((function_name->u.constant.value.str.len == sizeof(ZEND_CALL_FUNC_NAME)-1) && (!memcmp(function_name->u.constant.value.str.val, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)))) { + CG(active_class_entry)->__call = (zend_function *) CG(active_op_array); + } else if ((function_name->u.constant.value.str.len == sizeof(ZEND_GET_FUNC_NAME)-1) && (!memcmp(function_name->u.constant.value.str.val, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)))) { + CG(active_class_entry)->__get = (zend_function *) CG(active_op_array); + } else if ((function_name->u.constant.value.str.len == sizeof(ZEND_SET_FUNC_NAME)-1) && (!memcmp(function_name->u.constant.value.str.val, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)))) { + CG(active_class_entry)->__set = (zend_function *) CG(active_op_array); } } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -1501,6 +1503,9 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) function_add_ref(function); } ce->constructor = ce->parent->constructor; + ce->__get = ce->parent->__get; + ce->__set = ce->parent->__set; + ce->__call = ce->parent->__call; } void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) @@ -1551,6 +1556,9 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze new_class_entry->constructor = NULL; new_class_entry->destructor = NULL; new_class_entry->clone = NULL; + new_class_entry->__get = NULL; + new_class_entry->__set = NULL; + new_class_entry->__call = NULL; new_class_entry->create_object = NULL; new_class_entry->handle_function_call = NULL; @@ -2050,6 +2058,9 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod new_class_entry->constructor = NULL; new_class_entry->destructor = NULL; new_class_entry->clone = NULL; + new_class_entry->__get = NULL; + new_class_entry->__set = NULL; + new_class_entry->__call = NULL; new_class_entry->create_object = NULL; new_class_entry->handle_function_call = NULL; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 69f98864d7..94422bf766 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -710,4 +710,11 @@ int zendlex(znode *zendlval TSRMLS_DC); END_EXTERN_C() +#define ZEND_CLONE_FUNC_NAME "__clone" +#define ZEND_CONSTRUCTOR_FUNC_NAME "__construct" +#define ZEND_DESTRUCTOR_FUNC_NAME "__destruct" +#define ZEND_GET_FUNC_NAME "__get" +#define ZEND_SET_FUNC_NAME "__set" +#define ZEND_CALL_FUNC_NAME "__call" + #endif /* ZEND_COMPILE_H */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d397ccf387..fb10e0eda0 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -140,7 +140,7 @@ static inline zval **_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC) static inline zval **zend_fetch_property_address_inner(zval *object, znode *op2, temp_variable *Ts, int type TSRMLS_DC) { zval *prop_ptr = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); - zval **retval; + zval **retval = NULL; zval tmp; @@ -161,7 +161,9 @@ static inline zval **zend_fetch_property_address_inner(zval *object, znode *op2, if(Z_OBJ_HT_P(object)->get_property_ptr != NULL) { retval = Z_OBJ_HT_P(object)->get_property_ptr(object, prop_ptr TSRMLS_CC); - } else { + } + + if(retval == NULL) { zend_error(E_WARNING, "This object doesn't support property references"); retval = &EG(error_zval_ptr); } @@ -321,6 +323,7 @@ static inline void zend_assign_to_object_op(znode *result, znode *op1, znode *op zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); zval tmp; zval **retval = &Ts[result->u.var].var.ptr; + int have_get_ptr = 0; Ts[result->u.var].var.ptr_ptr = NULL; make_real_object(object_ptr TSRMLS_CC); @@ -356,12 +359,17 @@ static inline void zend_assign_to_object_op(znode *result, znode *op1, znode *op if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); - SEPARATE_ZVAL_IF_NOT_REF(zptr); + if(zptr != NULL) { /* NULL means no success in getting PTR */ + SEPARATE_ZVAL_IF_NOT_REF(zptr); - binary_op(*zptr, *zptr, value TSRMLS_CC); - *retval = *zptr; - SELECTIVE_PZVAL_LOCK(*retval, result); - } else { + have_get_ptr = 1; + binary_op(*zptr, *zptr, value TSRMLS_CC); + *retval = *zptr; + SELECTIVE_PZVAL_LOCK(*retval, result); + } + } + + if(!have_get_ptr) { zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); SEPARATE_ZVAL_IF_NOT_REF(&z); binary_op(z, z, value TSRMLS_CC); @@ -989,6 +997,7 @@ static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp zval *object; zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); zval **retval = &Ts[result->u.var].var.ptr; + int have_get_ptr = 0; make_real_object(object_ptr TSRMLS_CC); object = *object_ptr; @@ -1006,12 +1015,17 @@ static void zend_pre_incdec_property(znode *result, znode *op1, znode *op2, temp if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); - SEPARATE_ZVAL_IF_NOT_REF(zptr); + if(zptr != NULL) { /* NULL means no success in getting PTR */ + SEPARATE_ZVAL_IF_NOT_REF(zptr); - incdec_op(*zptr); - *retval = *zptr; - SELECTIVE_PZVAL_LOCK(*retval, result); - } else { + have_get_ptr = 1; + incdec_op(*zptr); + *retval = *zptr; + SELECTIVE_PZVAL_LOCK(*retval, result); + } + } + + if(!have_get_ptr) { zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); SEPARATE_ZVAL_IF_NOT_REF(&z); incdec_op(z); @@ -1030,6 +1044,7 @@ static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, tem zval *object; zval *property = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R); zval *retval = &Ts[result->u.var].tmp_var; + int have_get_ptr = 0; make_real_object(object_ptr TSRMLS_CC); object = *object_ptr; @@ -1045,13 +1060,19 @@ static void zend_post_incdec_property(znode *result, znode *op1, znode *op2, tem if(Z_OBJ_HT_P(object)->get_property_zval_ptr) { zval **zptr = Z_OBJ_HT_P(object)->get_property_zval_ptr(object, property TSRMLS_CC); - SEPARATE_ZVAL_IF_NOT_REF(zptr); + if(zptr != NULL) { /* NULL means no success in getting PTR */ + have_get_ptr = 1; + SEPARATE_ZVAL_IF_NOT_REF(zptr); + + *retval = **zptr; + zendi_zval_copy_ctor(*retval); + + incdec_op(*zptr); - *retval = **zptr; - zendi_zval_copy_ctor(*retval); + } + } - incdec_op(*zptr); - } else { + if(!have_get_ptr) { zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_RW TSRMLS_CC); SEPARATE_ZVAL_IF_NOT_REF(&z); *retval = *z; @@ -1627,6 +1648,8 @@ binary_assign_op_addr_obj: EX(Ts)[EX(opline)->result.u.var].tmp_var.value.str.val[0] = 0; EX(Ts)[EX(opline)->result.u.var].tmp_var.value.str.len = 0; EX(Ts)[EX(opline)->result.u.var].tmp_var.refcount = 1; + EX(Ts)[EX(opline)->result.u.var].tmp_var.type = IS_STRING; + EX(Ts)[EX(opline)->result.u.var].tmp_var.is_ref = 0; NEXT_OPCODE(); case ZEND_ADD_CHAR: add_char_to_string( &EX(Ts)[EX(opline)->result.u.var].tmp_var, @@ -2077,6 +2100,7 @@ do_fcall_common: ALLOC_ZVAL(EX(Ts)[EX(opline)->result.u.var].var.ptr); INIT_ZVAL(*(EX(Ts)[EX(opline)->result.u.var].var.ptr)); ((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object), return_value_used TSRMLS_CC); + EG(current_execute_data) = &execute_data; EX(Ts)[EX(opline)->result.u.var].var.ptr->is_ref = 0; EX(Ts)[EX(opline)->result.u.var].var.ptr->refcount = 1; if (!return_value_used) { @@ -2673,7 +2697,11 @@ send_by_ref: file_handle.free_filename = 0; if (file_handle.handle.fp) { - if (!opened_path || zend_hash_add(&EG(included_files), opened_path, strlen(opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) { + if( !opened_path ) { + opened_path = file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); + } + + if (zend_hash_add(&EG(included_files), opened_path, strlen(opened_path)+1, (void *)&dummy, sizeof(int), NULL)==SUCCESS) { new_op_array = zend_compile_file(&file_handle, (EX(opline)->op2.u.constant.value.lval==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); zend_destroy_file_handle(&file_handle TSRMLS_CC); opened_path = NULL; /* zend_destroy_file_handle() already frees it */ diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 7f7d8bce89..03a8304cd9 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -459,7 +459,6 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun int i; zval **original_return_value; HashTable *calling_symbol_table; - zend_function_state function_state; zend_function_state *original_function_state_ptr; zend_op_array *original_op_array; zend_op **original_opline_ptr; @@ -471,6 +470,14 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun zend_class_entry *calling_scope = NULL; zval *current_this; + zend_execute_data execute_data; + + /* Initialize execute_data */ + EX(fbc) = NULL; + EX(object) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; *retval_ptr_ptr = NULL; if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */ @@ -501,6 +508,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun } function_table = &Z_OBJCE_PP(object_pp)->function_table; + EX(object) = *object_pp; calling_scope = Z_OBJCE_PP(object_pp); } else if (Z_TYPE_PP(object_pp) == IS_STRING) { zend_class_entry **ce; @@ -530,7 +538,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun zend_str_tolower(function_name_copy.value.str.val, function_name_copy.value.str.len); original_function_state_ptr = EG(function_state_ptr); - if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &function_state.function)==FAILURE) { + if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { zval_dtor(&function_name_copy); return FAILURE; } @@ -539,9 +547,9 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun for (i=0; i<param_count; i++) { zval *param; - if (function_state.function->common.arg_types - && i<function_state.function->common.arg_types[0] - && function_state.function->common.arg_types[i+1]==BYREF_FORCE + if (EX(function_state).function->common.arg_types + && i<EX(function_state).function->common.arg_types[0] + && EX(function_state).function->common.arg_types[i+1]==BYREF_FORCE && !PZVAL_IS_REF(*params[i])) { if ((*params[i])->refcount>1) { zval *new_zval; @@ -572,7 +580,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) (long) param_count, NULL); - EG(function_state_ptr) = &function_state; + EG(function_state_ptr) = &EX(function_state); current_scope = EG(scope); EG(scope) = calling_scope; @@ -597,8 +605,10 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun EG(This) = NULL; } + EX(prev_execute_data) = EG(current_execute_data); + EG(current_execute_data) = &execute_data; - if (function_state.function->type == ZEND_USER_FUNCTION) { + if (EX(function_state).function->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); if (symbol_table) { EG(active_symbol_table) = symbol_table; @@ -610,7 +620,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun original_return_value = EG(return_value_ptr_ptr); original_op_array = EG(active_op_array); EG(return_value_ptr_ptr) = retval_ptr_ptr; - EG(active_op_array) = (zend_op_array *) function_state.function; + EG(active_op_array) = (zend_op_array *) EX(function_state).function; original_opline_ptr = EG(opline_ptr); orig_free_op1 = EG(free_op1); orig_free_op2 = EG(free_op2); @@ -631,7 +641,7 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun EG(binary_op) = orig_binary_op; } else { ALLOC_INIT_ZVAL(*retval_ptr_ptr); - ((zend_internal_function *) function_state.function)->handler(param_count, *retval_ptr_ptr, (object_pp?*object_pp:NULL), 1 TSRMLS_CC); + ((zend_internal_function *) EX(function_state).function)->handler(param_count, *retval_ptr_ptr, (object_pp?*object_pp:NULL), 1 TSRMLS_CC); INIT_PZVAL(*retval_ptr_ptr); } zend_ptr_stack_clear_multiple(TSRMLS_C); @@ -642,7 +652,8 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun } EG(scope) = current_scope; EG(This) = current_this; - + EG(current_execute_data) = EX(prev_execute_data); \ + return SUCCESS; } diff --git a/Zend/zend_extensions.c b/Zend/zend_extensions.c index 6e50ae1398..8104a583d8 100644 --- a/Zend/zend_extensions.c +++ b/Zend/zend_extensions.c @@ -33,7 +33,7 @@ int zend_load_extension(char *path) handle = DL_LOAD(path); if (!handle) { #ifndef ZEND_WIN32 - fprintf(stderr, "Failed loading %s: %s\n", path, dlerror()); + fprintf(stderr, "Failed loading %s: %s\n", path, DL_ERROR()); #else fprintf(stderr, "Failed loading %s\n", path); #endif diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h index 3f7e0ebfd3..0e540b72e6 100644 --- a/Zend/zend_extensions.h +++ b/Zend/zend_extensions.h @@ -23,7 +23,7 @@ #include "zend_compile.h" -#define ZEND_EXTENSION_API_NO 20010710 +#define ZEND_EXTENSION_API_NO 220020901 typedef struct _zend_extension_version_info { int zend_extension_api_no; diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 079069175b..3b01663945 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1109,7 +1109,7 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, IS_CONSISTENT(ht); - if (ht->nNumOfElements <= 1) { /* Doesn't require sorting */ + if (!(ht->nNumOfElements>1) && !(renumber && ht->nNumOfElements>0)) { /* Doesn't require sorting */ return SUCCESS; } arTmp = (Bucket **) pemalloc(ht->nNumOfElements * sizeof(Bucket *), ht->persistent); diff --git a/Zend/zend_ini.c b/Zend/zend_ini.c index 42e28379cc..cfeae83363 100644 --- a/Zend/zend_ini.c +++ b/Zend/zend_ini.c @@ -25,6 +25,8 @@ static HashTable *registered_zend_ini_directives; +#define NO_VALUE_PLAINTEXT "no value" +#define NO_VALUE_HTML "<i>no value</i>" /* * hash_apply functions @@ -305,15 +307,25 @@ static void zend_ini_displayer_cb(zend_ini_entry *ini_entry, int type) display_string = ini_entry->orig_value; display_string_length = ini_entry->orig_value_length; } else { - display_string = "<i>no value</i>"; - display_string_length = sizeof("<i>no value</i>")-1; + if(zend_uv.html_errors) { + display_string = NO_VALUE_HTML; + display_string_length = sizeof(NO_VALUE_HTML)-1; + } else { + display_string = NO_VALUE_PLAINTEXT; + display_string_length = sizeof(NO_VALUE_PLAINTEXT)-1; + } } } else if (ini_entry->value && ini_entry->value[0]) { display_string = ini_entry->value; display_string_length = ini_entry->value_length; } else { - display_string = "<i>no value</i>"; - display_string_length = sizeof("<i>no value</i>")-1; + if(zend_uv.html_errors) { + display_string = NO_VALUE_HTML; + display_string_length = sizeof(NO_VALUE_HTML)-1; + } else { + display_string = NO_VALUE_PLAINTEXT; + display_string_length = sizeof(NO_VALUE_PLAINTEXT)-1; + } } ZEND_WRITE(display_string, display_string_length); } @@ -351,9 +363,17 @@ ZEND_INI_DISP(zend_ini_color_displayer_cb) value = NULL; } if (value) { - zend_printf("<font color=\"%s\">%s</font>", value, value); + if (zend_uv.html_errors) { + zend_printf("<font color=\"%s\">%s</font>", value, value); + } else { + ZEND_PUTS(value); + } } else { - ZEND_PUTS("<i>no value</i>;"); + if (zend_uv.html_errors) { + ZEND_PUTS(NO_VALUE_HTML); + } else { + ZEND_PUTS(NO_VALUE_PLAINTEXT); + } } } diff --git a/Zend/zend_llist.c b/Zend/zend_llist.c index b9f8eb2b10..bb47f9b459 100644 --- a/Zend/zend_llist.c +++ b/Zend/zend_llist.c @@ -82,8 +82,8 @@ ZEND_API void zend_llist_prepend_element(zend_llist *l, void *element) }\ if ((l)->dtor) {\ (l)->dtor((current)->data);\ - pefree((current), (l)->persistent);\ }\ + pefree((current), (l)->persistent);\ --l->count; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 9c131e2626..caae823cc9 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -8,6 +8,23 @@ #define DEBUG_OBJECT_HANDLERS 0 +/* + __X accessors explanation: + + if we have __get and property that is not part of the properties array is + requested, we call __get handler. If it fails, we return uninitialized. + + if we have __set and property that is not part of the properties array is + set, we call __set handler. If it fails, we do not change the array. + + for both handlers above, when we are inside __get/__set, no further calls for + __get/__set for these objects will be made, to prevent endless recursion and + enable accessors to change properties array. + + if we have __call and method which is not part of the class function table is + called, we cal __call handler. +*/ + static HashTable *zend_std_get_properties(zval *object TSRMLS_DC) { zend_object *zobj; @@ -15,11 +32,109 @@ static HashTable *zend_std_get_properties(zval *object TSRMLS_DC) return zobj->properties; } +static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) +{ + zval **call_args[1]; + zval *retval = NULL; + zval __get_name; + int call_result; + + /* __get handler is called with two arguments: + property name + return value for the object (by reference) + + it should return whether the call was successfull or not + */ + INIT_PZVAL(&__get_name); + ZVAL_STRINGL(&__get_name, ZEND_GET_FUNC_NAME, sizeof(ZEND_GET_FUNC_NAME)-1, 0); + + call_args[0] = &member; + + /* go call the __get handler */ + call_result = call_user_function_ex(NULL, + &object, + &__get_name, + &retval, + 1, call_args, + 0, NULL TSRMLS_CC); + + /* + call_result is if call_user_function gone OK. + retval returns the value that is received + */ + + + if(call_result == FAILURE) { + zend_error(E_ERROR, "Could not call __get handler for class %s", Z_OBJCE_P(object)->name); + return NULL; + } + + retval->refcount--; + + return retval; +} + +static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC) +{ + zval **call_args[2]; + zval *retval = NULL; + zval __set_name; + int call_result; + int ret; + + /* __set handler is called with two arguments: + property name + value to be set + + it should return whether the call was successfull or not + */ + INIT_PZVAL(&__set_name); + ZVAL_STRINGL(&__set_name, ZEND_SET_FUNC_NAME, sizeof(ZEND_SET_FUNC_NAME)-1, 0); + + call_args[0] = &member; + value->refcount++; + call_args[1] = &value; + + /* go call the __set handler */ + call_result = call_user_function_ex(NULL, + &object, + &__set_name, + &retval, + 2, call_args, + 0, NULL TSRMLS_CC); + + /* + call_result is if call_user_function gone OK. + retval shows if __get method went OK. + */ + + + if(call_result == FAILURE) { + zend_error(E_ERROR, "Could not call __set handler for class %s", Z_OBJCE_P(object)->name); + return FAILURE; + } + + zval_ptr_dtor(&value); + + if (retval && zval_is_true(retval)) { + ret = SUCCESS; + } else { + ret = FAILURE; + } + + if(retval) { + zval_ptr_dtor(&retval); + } + + return ret; +} + zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) { zend_object *zobj; zval tmp_member; zval **retval; + zval *rv = NULL; zobj = Z_OBJ_P(object); @@ -35,25 +150,38 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) #endif if (zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &retval) == FAILURE) { - switch (type) { - case BP_VAR_R: - zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member)); - /* break missing intentionally */ - case BP_VAR_IS: - retval = &EG(uninitialized_zval_ptr); - break; - case BP_VAR_RW: - zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member)); - /* break missing intentionally */ - case BP_VAR_W: { + if(zobj->ce->__get && !zobj->in_get) { + /* have getter - try with it! */ + zobj->in_get = 1; /* prevent circular getting */ + rv = zend_std_call_getter(object, member TSRMLS_CC); + zobj->in_get = 0; + + if(rv) { + retval = &rv; + } else { + retval = &EG(uninitialized_zval_ptr); + } + } else { + switch (type) { + case BP_VAR_R: + zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member)); + /* break missing intentionally */ + case BP_VAR_IS: + retval = &EG(uninitialized_zval_ptr); + break; + case BP_VAR_RW: + zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member)); + /* break missing intentionally */ + case BP_VAR_W: { zval *new_zval = &EG(uninitialized_zval); - + new_zval->refcount++; zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &new_zval, sizeof(zval *), (void **) &retval); - } + } break; EMPTY_SWITCH_DEFAULT_CASE() - + + } } } if (member == &tmp_member) { @@ -67,6 +195,7 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM zend_object *zobj; zval tmp_member; zval **variable_ptr; + int setter_done = 0; zobj = Z_OBJ_P(object); @@ -88,10 +217,21 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM FREE_ZVAL(*variable_ptr); } } + } else { + if(zobj->ce->__set && !zobj->in_set) { + zobj->in_set = 1; /* prevent circular setting */ + if(zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) { +// zend_error(E_NOTICE,"Cannot set undefined property: %s", Z_STRVAL_P(member)); + } + setter_done = 1; + zobj->in_set = 0; + } } - value->refcount++; - zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &value, sizeof(zval *), NULL); + if(!setter_done) { + value->refcount++; + zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &value, sizeof(zval *), NULL); + } if (member == &tmp_member) { zval_dtor(member); } @@ -117,11 +257,19 @@ static zval **zend_std_get_property_ptr(zval *object, zval *member TSRMLS_DC) #endif if (zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &retval) == FAILURE) { - zval *new_zval = &EG(uninitialized_zval); + zval *new_zval; + + if(!zobj->ce->__get) { + /* we don't have getter - will just add it */ + new_zval = &EG(uninitialized_zval); - zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); - new_zval->refcount++; - zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); + new_zval->refcount++; + zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &new_zval, sizeof(zval *), (void **) &retval); + } else { + /* we do have getter - fail and let it try again with usual get/set */ + retval = NULL; + } } if (member == &tmp_member) { zval_dtor(member); @@ -148,12 +296,86 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC) } } +static void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) +{ + zval ***args; + zend_internal_function *func = (zend_internal_function *)EG(function_state_ptr)->function; + zval method_name, method_args, __call_name; + zval *method_name_ptr, *method_args_ptr; + zval **call_args[2]; + zval *method_result_ptr = NULL; + int i, call_result; + + args = (zval ***)emalloc(ZEND_NUM_ARGS() * sizeof(zval **)); + + if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { + efree(args); + zend_error(E_ERROR, "Cannot get arguments for __call"); + RETURN_FALSE; + } + + method_name_ptr = &method_name; + INIT_PZVAL(method_name_ptr); + ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ + + method_args_ptr = &method_args; + INIT_PZVAL(method_args_ptr); + array_init(method_args_ptr); + + for(i=0; i<ZEND_NUM_ARGS(); i++) { + zval_add_ref(args[i]); + add_next_index_zval(method_args_ptr, *args[i]); + } + + efree(args); + + INIT_PZVAL(&__call_name); + ZVAL_STRINGL(&__call_name, ZEND_CALL_FUNC_NAME, sizeof(ZEND_CALL_FUNC_NAME)-1, 0); + + /* __call handler is called with two arguments: + method name + array of method parameters + + */ + call_args[0] = &method_name_ptr; + call_args[1] = &method_args_ptr; + + /* go call the __call handler */ + call_result = call_user_function_ex(NULL, + &this_ptr, + &__call_name, + &method_result_ptr, + 2, call_args, + 0, NULL TSRMLS_CC); + + /* call_result is if call_user_function gone OK. + method_result_ptr is the true result of the called method + */ + + if(method_result_ptr) { + *return_value = *method_result_ptr; + zval_copy_ctor(return_value); + zval_ptr_dtor(&method_result_ptr); + } + + if(call_result == FAILURE) { + zend_error(E_ERROR, "Could not call __call handler for class %s", Z_OBJCE_P(this_ptr)->name); + } + + /* now destruct all auxiliaries */ + zval_dtor(method_args_ptr); + zval_dtor(method_name_ptr); + + /* destruct the function also, then - we have allocated it in get_method */ + efree(func); +} + static union _zend_function *zend_std_get_method(zval *object, char *method_name, int method_len TSRMLS_DC) { zend_object *zobj; zend_function *func_method; char *lc_method_name; - + lc_method_name = do_alloca(method_len+1); /* Create a zend_copy_str_tolower(dest, src, src_length); */ memcpy(lc_method_name, method_name, method_len+1); @@ -161,6 +383,17 @@ static union _zend_function *zend_std_get_method(zval *object, char *method_name zobj = Z_OBJ_P(object); if(zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&func_method) == FAILURE) { + if(zobj->ce->__call != NULL) { + zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function)); + call_user_call->type = ZEND_INTERNAL_FUNCTION; + call_user_call->handler = zend_std_call_user_call; + call_user_call->arg_types = NULL; + call_user_call->scope = NULL; + call_user_call->function_name = estrndup(method_name, method_len); + + free_alloca(lc_method_name); + return (union _zend_function *)call_user_call; + } zend_error(E_ERROR, "Call to undefined function %s()", method_name); } diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c index 3e253cc406..a6b7579350 100644 --- a/Zend/zend_objects.c +++ b/Zend/zend_objects.c @@ -57,6 +57,8 @@ ZEND_API zend_object_value zend_objects_new(zend_object **object, zend_class_ent (*object)->ce = class_type; retval.handle = zend_objects_store_put(*object, (zend_objects_store_dtor_t) zend_objects_destroy_object, NULL TSRMLS_CC); retval.handlers = &std_object_handlers; + (*object)->in_get = 0; + (*object)->in_set = 0; return retval; } diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 897d807020..50b9e7555b 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -36,7 +36,7 @@ ZEND_API int zend_atoi(const char *str, int str_len) if (!str_len) { str_len = strlen(str); } - retval = atoi(str); + retval = strtol(str, NULL, 0); if (str_len>0) { switch (str[str_len-1]) { case 'k': @@ -871,7 +871,7 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result_str[i] |= shorter->value.str.val[i]; } if (result==op1) { - efree(result->value.str.val); + STR_FREE(result->value.str.val); } result->value.str.val = result_str; result->value.str.len = result_len; @@ -910,7 +910,7 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result_str[i] &= longer->value.str.val[i]; } if (result==op1) { - efree(result->value.str.val); + STR_FREE(result->value.str.val); } result->value.str.val = result_str; result->value.str.len = result_len; @@ -951,7 +951,7 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) result_str[i] ^= longer->value.str.val[i]; } if (result==op1) { - efree(result->value.str.val); + STR_FREE(result->value.str.val); } result->value.str.val = result_str; result->value.str.len = result_len; @@ -1489,12 +1489,12 @@ ZEND_API int increment_function(zval *op1) op1->value.lval = lval+1; op1->type = IS_LONG; } - efree(strval); + efree(strval); /* should never be empty_string */ break; case IS_DOUBLE: op1->value.dval = dval+1; op1->type = IS_DOUBLE; - efree(strval); + efree(strval); /* should never be empty_string */ break; #if 0 case FLAG_IS_BC: |