diff options
Diffstat (limited to 'Zend/zend_object_handlers.c')
-rw-r--r-- | Zend/zend_object_handlers.c | 67 |
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) { |