mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Simplify/Optmize magic method calls (__get/__set/__call/__clone/__destruct)
This commit is contained in:
parent
72b2d1c9ee
commit
e39f3f3f48
@ -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));
|
||||
|
@ -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) \
|
||||
|
@ -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,50 +497,19 @@ 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;
|
||||
zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, 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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user