Simplify/Optmize magic method calls (__get/__set/__call/__clone/__destruct)

This commit is contained in:
Marcus Boerger 2004-09-28 22:55:22 +00:00
parent 72b2d1c9ee
commit e39f3f3f48
4 changed files with 45 additions and 115 deletions

View File

@ -159,6 +159,28 @@ ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_arr
} }
ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC)
{
void **p;
int arg_count;
p = EG(argument_stack).top_element-2;
arg_count = (ulong) *p;
if (param_count>arg_count) {
return FAILURE;
}
while (param_count-->0) {
zval **param = (zval **) p-(arg_count--);
zval_add_ref(param);
add_next_index_zval(argument_array, *param);
}
return SUCCESS;
}
ZEND_API void zend_wrong_param_count(TSRMLS_D) ZEND_API void zend_wrong_param_count(TSRMLS_D)
{ {
zend_error(E_WARNING, "Wrong parameter count for %s()", get_active_function_name(TSRMLS_C)); zend_error(E_WARNING, "Wrong parameter count for %s()", get_active_function_name(TSRMLS_C));

View File

@ -146,6 +146,9 @@ ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval **argument
ZEND_API int zend_get_parameters_ex(int param_count, ...); ZEND_API int zend_get_parameters_ex(int param_count, ...);
ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_array TSRMLS_DC); ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_array TSRMLS_DC);
/* internal function to efficiently copy parameters when executing __call() */
ZEND_API int zend_copy_parameters_array(int param_count, zval *argument_array TSRMLS_DC);
#define zend_get_parameters_array(ht, param_count, argument_array) \ #define zend_get_parameters_array(ht, param_count, argument_array) \
_zend_get_parameters_array(ht, param_count, argument_array TSRMLS_CC) _zend_get_parameters_array(ht, param_count, argument_array TSRMLS_CC)
#define zend_get_parameters_array_ex(param_count, argument_array) \ #define zend_get_parameters_array_ex(param_count, argument_array) \

View File

@ -58,40 +58,16 @@ static HashTable *zend_std_get_properties(zval *object TSRMLS_DC)
static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC)
{ {
zval **call_args[1];
zval *retval = NULL; zval *retval = NULL;
zval __get_name; zend_class_entry *ce = Z_OBJCE_P(object);
int call_result;
/* __get handler is called with two arguments: /* __get handler is called with one argument:
property name property name
return value for the object (by reference)
it should return whether the call was successfull or not it should return whether the call was successfull or not
*/ */
INIT_PZVAL(&__get_name); zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
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;
}
if (retval) { if (retval) {
retval->refcount--; retval->refcount--;
} }
@ -101,43 +77,19 @@ static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC)
static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC) static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC)
{ {
zval **call_args[2];
zval *retval = NULL; zval *retval = NULL;
zval __set_name;
int call_result;
int ret; int ret;
zend_class_entry *ce = Z_OBJCE_P(object);
value->refcount++;
/* __set handler is called with two arguments: /* __set handler is called with two arguments:
property name property name
value to be set value to be set
it should return whether the call was successfull or not it should return whether the call was successfull or not
*/ */
INIT_PZVAL(&__set_name); zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
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); zval_ptr_dtor(&value);
@ -525,18 +477,18 @@ static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC)
ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
{ {
zval ***args;
zend_internal_function *func = (zend_internal_function *)EG(function_state_ptr)->function; zend_internal_function *func = (zend_internal_function *)EG(function_state_ptr)->function;
zval method_name, method_args, __call_name; zval method_name, method_args;
zval *method_name_ptr, *method_args_ptr; zval *method_name_ptr, *method_args_ptr;
zval **call_args[2];
zval *method_result_ptr = NULL; zval *method_result_ptr = NULL;
int i, call_result; zend_class_entry *ce = Z_OBJCE_P(this_ptr);
args = (zval ***)emalloc(ZEND_NUM_ARGS() * sizeof(zval **)); method_args_ptr = &method_args;
INIT_PZVAL(method_args_ptr);
array_init(method_args_ptr);
if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) { if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
efree(args); zval_dtor(method_args_ptr);
zend_error(E_ERROR, "Cannot get arguments for __call"); zend_error(E_ERROR, "Cannot get arguments for __call");
RETURN_FALSE; RETURN_FALSE;
} }
@ -545,50 +497,19 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
INIT_PZVAL(method_name_ptr); INIT_PZVAL(method_name_ptr);
ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */ 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: /* __call handler is called with two arguments:
method name method name
array of method parameters array of method parameters
*/ */
call_args[0] = &method_name_ptr; zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_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) { if (method_result_ptr) {
*return_value = *method_result_ptr; *return_value = *method_result_ptr;
zval_copy_ctor(return_value); zval_copy_ctor(return_value);
zval_ptr_dtor(&method_result_ptr); 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 */ /* now destruct all auxiliaries */
zval_dtor(method_args_ptr); zval_dtor(method_args_ptr);
zval_dtor(method_name_ptr); zval_dtor(method_name_ptr);

View File

@ -75,7 +75,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl
*/ */
old_exception = EG(exception); old_exception = EG(exception);
EG(exception) = NULL; EG(exception) = NULL;
zend_call_method_with_0_params(&obj, object->ce, NULL, "__destruct", NULL); zend_call_method_with_0_params(&obj, object->ce, &object->ce->destructor, ZEND_DESTRUCTOR_FUNC_NAME, NULL);
if (old_exception) { if (old_exception) {
if (EG(exception)) { if (EG(exception)) {
zend_error(E_ERROR, "Ignoring exception from %s::__destruct() while an exception is already active", object->ce->name); zend_error(E_ERROR, "Ignoring exception from %s::__destruct() while an exception is already active", object->ce->name);
@ -116,31 +116,15 @@ ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object_va
zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *)); zend_hash_copy(new_object->properties, old_object->properties, (copy_ctor_func_t) zval_add_ref, (void *) NULL /* Not used anymore */, sizeof(zval *));
if (old_object->ce->clone) { if (old_object->ce->clone) {
zval *new_obj; zval *new_obj;
zval *clone_func_name;
zval *retval_ptr;
HashTable symbol_table;
MAKE_STD_ZVAL(new_obj); MAKE_STD_ZVAL(new_obj);
new_obj->type = IS_OBJECT; new_obj->type = IS_OBJECT;
new_obj->value.obj = new_obj_val; new_obj->value.obj = new_obj_val;
zval_copy_ctor(new_obj); zval_copy_ctor(new_obj);
/* FIXME: Optimize this so that we use the old_object->ce->clone function pointer instead of the name */ zend_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
MAKE_STD_ZVAL(clone_func_name);
clone_func_name->type = IS_STRING;
clone_func_name->value.str.val = estrndup("__clone", sizeof("__clone")-1);
clone_func_name->value.str.len = sizeof("__clone")-1;
ZEND_INIT_SYMTABLE(&symbol_table);
call_user_function_ex(NULL, &new_obj, clone_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC);
zend_hash_destroy(&symbol_table);
zval_ptr_dtor(&new_obj); zval_ptr_dtor(&new_obj);
zval_ptr_dtor(&clone_func_name);
if(retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
} }
} }