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_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_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) \
_zend_get_parameters_array(ht, param_count, argument_array TSRMLS_CC)
#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)
{
zval **call_args[1];
zval *retval = NULL;
zval __get_name;
int call_result;
zend_class_entry *ce = Z_OBJCE_P(object);
/* __get handler is called with two arguments:
property name
return value for the object (by reference)
/* __get handler is called with one argument:
property name
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);
zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
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) {
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)
{
zval **call_args[2];
zval *retval = NULL;
zval __set_name;
int call_result;
int ret;
zend_class_entry *ce = Z_OBJCE_P(object);
value->refcount++;
/* __set handler is called with two arguments:
property name
value to be set
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;
}
zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, 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)
{
zval ***args;
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 **call_args[2];
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) {
efree(args);
if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
zval_dtor(method_args_ptr);
zend_error(E_ERROR, "Cannot get arguments for __call");
RETURN_FALSE;
}
@ -545,39 +497,12 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
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
*/
zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
if (method_result_ptr) {
*return_value = *method_result_ptr;
@ -585,10 +510,6 @@ ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
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);

View File

@ -75,7 +75,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object, zend_object_handl
*/
old_exception = EG(exception);
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 (EG(exception)) {
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 *));
if (old_object->ce->clone) {
zval *new_obj;
zval *clone_func_name;
zval *retval_ptr;
HashTable symbol_table;
MAKE_STD_ZVAL(new_obj);
new_obj->type = IS_OBJECT;
new_obj->value.obj = new_obj_val;
zval_copy_ctor(new_obj);
/* FIXME: Optimize this so that we use the old_object->ce->clone function pointer instead of the name */
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_call_method_with_0_params(&new_obj, old_object->ce, &old_object->ce->clone, ZEND_CLONE_FUNC_NAME, NULL);
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(&clone_func_name);
if(retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
}
}