summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorSVN Migration <svn@php.net>2002-09-08 15:38:45 +0000
committerSVN Migration <svn@php.net>2002-09-08 15:38:45 +0000
commite94c67742f6f4bf9fe9a381273d1ea6a16db5ec3 (patch)
tree7cb16c2c460931bbf4798a79167770dfb48ff643 /Zend
parent6c22f90b4a3d24a8da83e78f8eef97cba6c05197 (diff)
downloadphp-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/ChangeLog202
-rw-r--r--Zend/ZEND_CHANGES78
-rw-r--r--Zend/Zend.m42
-rw-r--r--Zend/zend.c7
-rw-r--r--Zend/zend.h12
-rw-r--r--Zend/zend_builtin_functions.c143
-rw-r--r--Zend/zend_compile.c19
-rw-r--r--Zend/zend_compile.h7
-rw-r--r--Zend/zend_execute.c64
-rw-r--r--Zend/zend_execute_API.c31
-rw-r--r--Zend/zend_extensions.c2
-rw-r--r--Zend/zend_extensions.h2
-rw-r--r--Zend/zend_hash.c2
-rw-r--r--Zend/zend_ini.c32
-rw-r--r--Zend/zend_llist.c2
-rw-r--r--Zend/zend_object_handlers.c275
-rw-r--r--Zend/zend_objects.c2
-rw-r--r--Zend/zend_operators.c12
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: