summaryrefslogtreecommitdiff
path: root/Zend/zend_object_handlers.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_object_handlers.c')
-rw-r--r--Zend/zend_object_handlers.c67
1 files changed, 48 insertions, 19 deletions
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 221dbbe37..b09668b0d 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
- | Copyright (c) 1998-2008 Zend Technologies Ltd. (http://www.zend.com) |
+ | Copyright (c) 1998-2009 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -17,7 +17,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: zend_object_handlers.c,v 1.135.2.6.2.28 2008/02/21 13:55:22 dmitry Exp $ */
+/* $Id: zend_object_handlers.c,v 1.135.2.6.2.32 2009/02/17 17:09:05 iliaa Exp $ */
#include "zend.h"
#include "zend_globals.h"
@@ -328,6 +328,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
!guard->in_get) {
/* have getter - try with it! */
+ ZVAL_ADDREF(object);
guard->in_get = 1; /* prevent circular getting */
rv = zend_std_call_getter(object, member TSRMLS_CC);
guard->in_get = 0;
@@ -352,6 +353,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
} else {
retval = &EG(uninitialized_zval_ptr);
}
+ zval_ptr_dtor(&object);
} else {
if (!silent) {
zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member));
@@ -422,12 +424,14 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
if (zobj->ce->__set &&
zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
!guard->in_set) {
+ ZVAL_ADDREF(object);
guard->in_set = 1; /* prevent circular setting */
if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
/* for now, just ignore it - __set should take care of warnings, etc. */
}
setter_done = 1;
guard->in_set = 0;
+ zval_ptr_dtor(&object);
}
if (!setter_done && property_info) {
zval **foo;
@@ -468,6 +472,10 @@ zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
}
return 0;
}
+ if (EG(exception)) {
+ zval_ptr_dtor(&retval);
+ return 0;
+ }
/* Undo PZVAL_LOCK() */
retval->refcount--;
@@ -602,9 +610,11 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
!guard->in_unset) {
/* have unseter - try with it! */
+ ZVAL_ADDREF(object);
guard->in_unset = 1; /* prevent circular unsetting */
zend_std_call_unsetter(object, member TSRMLS_CC);
guard->in_unset = 0;
+ zval_ptr_dtor(&object);
}
}
@@ -752,6 +762,24 @@ static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc
}
+static inline union _zend_function *zend_get_user_call_function(zend_object *zobj, char *method_name, int method_len) /* {{{ */
+{
+ zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
+ call_user_call->type = ZEND_INTERNAL_FUNCTION;
+ call_user_call->module = zobj->ce->module;
+ call_user_call->handler = zend_std_call_user_call;
+ call_user_call->arg_info = NULL;
+ call_user_call->num_args = 0;
+ call_user_call->scope = zobj->ce;
+ call_user_call->fn_flags = 0;
+ call_user_call->function_name = estrndup(method_name, method_len);
+ call_user_call->pass_rest_by_reference = 0;
+ call_user_call->return_reference = ZEND_RETURN_VALUE;
+
+ return (union _zend_function *)call_user_call;
+}
+/* }}} */
+
static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC)
{
zend_object *zobj;
@@ -768,19 +796,7 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) {
free_alloca_with_limit(lc_method_name, use_heap);
if (zobj->ce->__call) {
- zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
- call_user_call->type = ZEND_INTERNAL_FUNCTION;
- call_user_call->module = zobj->ce->module;
- call_user_call->handler = zend_std_call_user_call;
- call_user_call->arg_info = NULL;
- call_user_call->num_args = 0;
- call_user_call->scope = zobj->ce;
- call_user_call->fn_flags = 0;
- call_user_call->function_name = estrndup(method_name, method_len);
- call_user_call->pass_rest_by_reference = 0;
- call_user_call->return_reference = ZEND_RETURN_VALUE;
-
- return (union _zend_function *)call_user_call;
+ return zend_get_user_call_function(zobj, method_name, method_len);
} else {
return NULL;
}
@@ -791,12 +807,18 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
zend_function *updated_fbc;
/* Ensure that if we're calling a private function, we're allowed to do so.
+ * If we're not and __call() handler exists, invoke it, otherwise error out.
*/
updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC);
- if (!updated_fbc) {
- zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
+ if (updated_fbc) {
+ fbc = updated_fbc;
+ } else {
+ if (zobj->ce->__call) {
+ fbc = zend_get_user_call_function(zobj, method_name, method_len);
+ } else {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
+ }
}
- fbc = updated_fbc;
} else {
/* Ensure that we haven't overridden a private function and end up calling
* the overriding public function...
@@ -814,9 +836,14 @@ static union _zend_function *zend_std_get_method(zval **object_ptr, char *method
}
if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
/* Ensure that if we're calling a protected function, we're allowed to do so.
+ * If we're not and __call() handler exists, invoke it, otherwise error out.
*/
if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
- zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
+ if (zobj->ce->__call) {
+ fbc = zend_get_user_call_function(zobj, method_name, method_len);
+ } else {
+ zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
+ }
}
}
}
@@ -1020,6 +1047,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists
zval *rv;
/* have issetter - try with it! */
+ ZVAL_ADDREF(object);
guard->in_isset = 1; /* prevent circular getting */
rv = zend_std_call_issetter(object, member TSRMLS_CC);
if (rv) {
@@ -1037,6 +1065,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists
}
}
guard->in_isset = 0;
+ zval_ptr_dtor(&object);
}
} else {
switch (has_set_exists) {