Remove ZEND_OVERLOADED_FUNCTION and corresponding call_method object handler

This commit is contained in:
Dmitry Stogov 2019-02-07 21:05:46 +03:00
parent 2306c855ab
commit f45e0ce928
18 changed files with 94 additions and 259 deletions

View file

@ -2,6 +2,7 @@ PHP 8.0 INTERNALS UPGRADE NOTES
1. Internal API changes
a. Object Handlers API
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
2. Build system changes
a. Abstract
@ -18,6 +19,11 @@ PHP 8.0 INTERNALS UPGRADE NOTES
zend_objects_clone_obj() were changed to receive zend_object* instead of
zval* and zend_string* instead of zval* for property names.
b. ZEND_OVERLOADED_FUNCTION and corresponding call_method() object handler
were removed. ZEND_INTERNAL_FUNCTION with ZEND_ACC_CALL_VIA_HANDLER and
defined "handler" callback should be used instead. This "handler" callback
should also take care about function cleanup. See ext/zend_test/test.c
for example.
========================
2. Build system changes

View file

@ -6,10 +6,10 @@ if (!extension_loaded('zend-test')) die('skip zend-test extension not loaded');
?>
--FILE--
<?php
$o = new _ZendTestChildClass();
var_dump($o->test());
var_dump(_ZendTestClass::test());
?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot call overloaded function for non-object in %soverloaded_func_001.php:%d
Stack trace:
#0 {main}
thrown in %soverloaded_func_001.php on line %d
--EXPECT--
string(4) "test"
string(4) "test"

View file

@ -3014,8 +3014,7 @@ get_function_via_handler:
(!fcc->function_handler->common.scope ||
!instanceof_function(ce_org, fcc->function_handler->common.scope))) {
if (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION &&
fcc->function_handler->common.function_name) {
if (fcc->function_handler->common.function_name) {
zend_string_release_ex(fcc->function_handler->common.function_name, 0);
}
zend_free_trampoline(fcc->function_handler);
@ -3206,11 +3205,8 @@ check_func:
ret = zend_is_callable_check_func(check_flags, callable, fcc, strict_class, error);
if (fcc == &fcc_local &&
fcc->function_handler &&
((fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
fcc->function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
if (fcc->function_handler->type != ZEND_OVERLOADED_FUNCTION &&
fcc->function_handler->common.function_name) {
(fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
if (fcc->function_handler->common.function_name) {
zend_string_release_ex(fcc->function_handler->common.function_name, 0);
}
zend_free_trampoline(fcc->function_handler);
@ -3322,12 +3318,8 @@ ZEND_API zend_bool zend_make_callable(zval *callable, zend_string **callable_nam
add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
}
if (fcc.function_handler &&
((fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) ||
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY ||
fcc.function_handler->type == ZEND_OVERLOADED_FUNCTION)) {
if (fcc.function_handler->type != ZEND_OVERLOADED_FUNCTION) {
(fcc.function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
zend_string_release_ex(fcc.function_handler->common.function_name, 0);
}
zend_free_trampoline(fcc.function_handler);
}
return 1;

View file

@ -875,9 +875,7 @@ void zend_assert_valid_class_name(const zend_string *const_name);
#define ZEND_INTERNAL_FUNCTION 1
#define ZEND_USER_FUNCTION 2
#define ZEND_OVERLOADED_FUNCTION 3
#define ZEND_EVAL_CODE 4
#define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5
/* A quick check (type == ZEND_USER_FUNCTION || type == ZEND_EVAL_CODE) */
#define ZEND_USER_CODE(type) ((type & 1) == 0)

View file

@ -4069,43 +4069,6 @@ already_compiled:
}
/* }}} */
ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zval *ret) /* {{{ */
{
zend_function *fbc = call->func;
zend_object *object;
/* Not sure what should be done here if it's a static method */
if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release_ex(fbc->common.function_name, 0);
}
efree(fbc);
zend_vm_stack_free_call_frame(call);
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
return 0;
}
object = Z_OBJ(call->This);
ZVAL_NULL(ret);
EG(current_execute_data) = call;
object->handlers->call_method(fbc->common.function_name, object, call, ret);
EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call);
if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release_ex(fbc->common.function_name, 0);
}
efree(fbc);
return 1;
}
/* }}} */
static zend_never_inline zend_bool ZEND_FASTCALL zend_fe_reset_iterator(zval *array_ptr, int by_ref OPLINE_DC EXECUTE_DATA_DC) /* {{{ */
{
zend_class_entry *ce = Z_OBJCE_P(array_ptr);

View file

@ -375,8 +375,6 @@ ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table);
ZEND_API void zend_free_compiled_variables(zend_execute_data *execute_data);
ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num);
ZEND_API int ZEND_FASTCALL zend_do_fcall_overloaded(zend_execute_data *call, zval *ret);
#define CACHE_ADDR(num) \
((void**)((char*)EX_RUN_TIME_CACHE() + (num)))

View file

@ -772,8 +772,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
/* We must re-initialize function again */
fci_cache->function_handler = NULL;
}
} else if (func->type == ZEND_INTERNAL_FUNCTION) {
} else {
int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
ZVAL_NULL(fci->retval);
call->prev_execute_data = EG(current_execute_data);
call->return_value = NULL; /* this is not a constructor call */
@ -796,30 +798,6 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
/* We must re-initialize function again */
fci_cache->function_handler = NULL;
}
} else { /* ZEND_OVERLOADED_FUNCTION */
ZVAL_NULL(fci->retval);
/* Not sure what should be done here if it's a static method */
if (fci->object) {
call->prev_execute_data = EG(current_execute_data);
EG(current_execute_data) = call;
fci->object->handlers->call_method(func->common.function_name, fci->object, call, fci->retval);
EG(current_execute_data) = call->prev_execute_data;
} else {
zend_throw_error(NULL, "Cannot call overloaded function for non-object");
}
zend_vm_stack_free_args(call);
if (func->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
zend_string_release_ex(func->common.function_name, 0);
}
efree(func);
if (EG(exception)) {
zval_ptr_dtor(fci->retval);
ZVAL_UNDEF(fci->retval);
}
}
zend_vm_stack_free_call_frame(call);

View file

@ -44,7 +44,6 @@ static const zend_object_handlers iterator_object_handlers = {
NULL, /* unset dim */
NULL, /* props get */
NULL, /* method get */
NULL, /* call */
NULL, /* get ctor */
NULL, /* get class name */
NULL, /* compare */

View file

@ -1845,7 +1845,6 @@ ZEND_API const zend_object_handlers std_object_handlers = {
zend_std_unset_dimension, /* unset_dimension */
zend_std_get_properties, /* get_properties */
zend_std_get_method, /* get_method */
NULL, /* call_method */
zend_std_get_constructor, /* get_constructor */
zend_std_get_class_name, /* get_class_name */
zend_std_compare_objects, /* compare_objects */

View file

@ -120,7 +120,6 @@ typedef zend_array *(*zend_object_get_properties_for_t)(zend_object *object, zen
/* args on stack! */
/* Andi - EX(fbc) (function being called) needs to be initialized already in the INIT fcall opcode so that the parameters can be parsed the right way. We need to add another callback for this.
*/
typedef int (*zend_object_call_method_t)(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS);
typedef zend_function *(*zend_object_get_method_t)(zend_object **object, zend_string *method, const zval *key);
typedef zend_function *(*zend_object_get_constructor_t)(zend_object *object);
@ -171,7 +170,6 @@ struct _zend_object_handlers {
zend_object_unset_dimension_t unset_dimension; /* required */
zend_object_get_properties_t get_properties; /* required */
zend_object_get_method_t get_method; /* required */
zend_object_call_method_t call_method; /* optional */
zend_object_get_constructor_t get_constructor; /* required */
zend_object_get_class_name_t get_class_name; /* required */
zend_object_compare_t compare_objects; /* optional */

View file

@ -4019,9 +4019,10 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -4053,22 +4054,6 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
EG(current_execute_data) = execute_data;
zend_vm_stack_free_args(call);
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(ret);
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
UNDEF_RESULT();
HANDLE_EXCEPTION();
}
if (!RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(ret);
}

View file

@ -963,9 +963,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -997,22 +998,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
EG(current_execute_data) = execute_data;
zend_vm_stack_free_args(call);
if (!0) {
zval_ptr_dtor(ret);
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
ret = 0 ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
UNDEF_RESULT();
HANDLE_EXCEPTION();
}
if (!0) {
zval_ptr_dtor(ret);
}
@ -1084,9 +1069,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
zend_execute_ex(call);
}
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
} else {
zval retval;
ZEND_ASSERT(fbc->type == ZEND_INTERNAL_FUNCTION);
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
@ -1118,22 +1104,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
EG(current_execute_data) = execute_data;
zend_vm_stack_free_args(call);
if (!1) {
zval_ptr_dtor(ret);
}
} else { /* ZEND_OVERLOADED_FUNCTION */
zval retval;
ret = 1 ? EX_VAR(opline->result.var) : &retval;
call->prev_execute_data = execute_data;
if (UNEXPECTED(!zend_do_fcall_overloaded(call, ret))) {
UNDEF_RESULT();
HANDLE_EXCEPTION();
}
if (!1) {
zval_ptr_dtor(ret);
}

View file

@ -246,11 +246,42 @@ static void function_dtor(zval *zv)
static PHP_FUNCTION(com_method_handler)
{
zval *object = getThis();
zend_string *method = EX(func)->common.function_name;
zval *args = NULL;
php_com_dotnet_object *obj = CDNO_FETCH(object);
int nargs;
VARIANT v;
int ret = FAILURE;
Z_OBJ_HANDLER_P(object, call_method)(
((zend_internal_function*)EX(func))->function_name,
Z_OBJ_P(object),
INTERNAL_FUNCTION_PARAM_PASSTHRU);
if (V_VT(&obj->v) != VT_DISPATCH) {
goto exit;
}
nargs = ZEND_NUM_ARGS();
if (nargs) {
args = (zval *)safe_emalloc(sizeof(zval), nargs, 0);
zend_get_parameters_array_ex(nargs, args);
}
VariantInit(&v);
if (SUCCESS == php_com_do_invoke_byref(obj, (zend_internal_function*)EX(func), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args)) {
php_com_zval_from_variant(return_value, &v, obj->code_page);
ret = SUCCESS;
VariantClear(&v);
}
if (args) {
efree(args);
}
exit:
/* Cleanup trampoline */
ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
zend_string_release(EX(func)->common.function_name);
zend_free_trampoline(EX(func));
EX(func) = NULL;
}
static zend_function *com_method_get(zend_object **object_ptr, zend_string *name, const zval *key)
@ -270,7 +301,8 @@ static zend_function *com_method_get(zend_object **object_ptr, zend_string *name
/* check cache */
if (obj->method_cache == NULL || NULL == (fptr = zend_hash_find_ptr(obj->method_cache, name))) {
f.type = ZEND_OVERLOADED_FUNCTION;
memset(&f, 0, sizeof(zend_internal_function));
f.type = ZEND_INTERNAL_FUNCTION;
f.num_args = 0;
f.arg_info = NULL;
f.scope = obj->ce;
@ -345,6 +377,7 @@ static zend_function *com_method_get(zend_object **object_ptr, zend_string *name
if (fptr) {
/* duplicate this into a new chunk of emalloc'd memory,
* since the engine will efree it */
zend_string_addref(fptr->function_name);
func = emalloc(sizeof(*fptr));
memcpy(func, fptr, sizeof(*fptr));
@ -354,40 +387,6 @@ static zend_function *com_method_get(zend_object **object_ptr, zend_string *name
return NULL;
}
static int com_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
{
zval *args = NULL;
php_com_dotnet_object *obj = (php_com_dotnet_object*)object;
int nargs;
VARIANT v;
int ret = FAILURE;
if (V_VT(&obj->v) != VT_DISPATCH) {
return FAILURE;
}
nargs = ZEND_NUM_ARGS();
if (nargs) {
args = (zval *)safe_emalloc(sizeof(zval), nargs, 0);
zend_get_parameters_array_ex(nargs, args);
}
VariantInit(&v);
if (SUCCESS == php_com_do_invoke_byref(obj, (zend_internal_function*)EX(func), DISPATCH_METHOD|DISPATCH_PROPERTYGET, &v, nargs, args)) {
php_com_zval_from_variant(return_value, &v, obj->code_page);
ret = SUCCESS;
VariantClear(&v);
}
if (args) {
efree(args);
}
return ret;
}
static zend_function *com_constructor_get(zend_object *object)
{
php_com_dotnet_object *obj = (php_com_dotnet_object *) object;
@ -554,7 +553,6 @@ zend_object_handlers php_com_object_handlers = {
com_dimension_delete,
com_properties_get,
com_method_get,
com_call_method,
com_constructor_get,
com_class_name_get,
com_objects_compare,

View file

@ -319,11 +319,6 @@ static zend_function *saproxy_method_get(zend_object **object, zend_string *name
return NULL;
}
static int saproxy_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
{
return FAILURE;
}
static zend_function *saproxy_constructor_get(zend_object *object)
{
/* user cannot instantiate */
@ -410,7 +405,6 @@ zend_object_handlers php_com_saproxy_handlers = {
saproxy_dimension_delete,
saproxy_properties_get,
saproxy_method_get,
saproxy_call_method,
saproxy_constructor_get,
saproxy_class_name_get,
saproxy_objects_compare,

View file

@ -2656,11 +2656,6 @@ static zend_function *row_method_get(
return fbc;
}
static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
{
return FAILURE;
}
static zend_function *row_get_ctor(zend_object *object)
{
zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
@ -2739,7 +2734,6 @@ void pdo_stmt_init(void)
pdo_row_object_handlers.unset_dimension = row_dim_delete;
pdo_row_object_handlers.get_properties_for = row_get_properties_for;
pdo_row_object_handlers.get_method = row_method_get;
pdo_row_object_handlers.call_method = row_call_method;
pdo_row_object_handlers.get_constructor = row_get_ctor;
pdo_row_object_handlers.get_class_name = row_get_classname;
pdo_row_object_handlers.compare_objects = row_compare;

View file

@ -2341,9 +2341,7 @@ ZEND_METHOD(reflection_parameter, __construct)
position= (int)Z_LVAL_P(parameter);
if (position < 0 || (uint32_t)position >= num_args) {
if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release_ex(fptr->common.function_name, 0);
}
zend_free_trampoline(fptr);
}
if (is_closure) {
@ -2380,9 +2378,7 @@ ZEND_METHOD(reflection_parameter, __construct)
}
if (position == -1) {
if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
zend_string_release_ex(fptr->common.function_name, 0);
}
zend_free_trampoline(fptr);
}
if (is_closure) {

View file

@ -1367,47 +1367,6 @@ static zend_function *spl_dual_it_get_method(zend_object **object, zend_string *
return function_handler;
}
#if MBO_0
int spl_dual_it_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
{
zval ***func_params, func;
zval retval;
int arg_count;
int current = 0;
int success;
void **p;
spl_dual_it_object *intern;
intern = Z_SPLDUAL_IT_P(ZEND_THIS);
ZVAL_STRING(&func, method, 0);
p = EG(argument_stack).top_element-2;
arg_count = (zend_ulong) *p;
func_params = safe_emalloc(sizeof(zval **), arg_count, 0);
current = 0;
while (arg_count-- > 0) {
func_params[current] = (zval **) p - (arg_count-current);
current++;
}
arg_count = current; /* restore */
if (call_user_function_ex(EG(function_table), NULL, &func, &retval, arg_count, func_params, 0, NULL) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
RETURN_ZVAL(&retval, 0, 0);
success = SUCCESS;
} else {
zend_throw_error(NULL, "Unable to call %s::%s()", intern->inner.ce->name, method);
success = FAILURE;
}
efree(func_params);
return success;
}
#endif
#define SPL_CHECK_CTOR(intern, classname) \
if (intern->dit_type == DIT_Unknown) { \
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Classes derived from %s must call %s::__construct()", \
@ -3682,7 +3641,6 @@ PHP_MINIT_FUNCTION(spl_iterators)
memcpy(&spl_handlers_dual_it, &std_object_handlers, sizeof(zend_object_handlers));
spl_handlers_dual_it.offset = XtOffsetOf(spl_dual_it_object, std);
spl_handlers_dual_it.get_method = spl_dual_it_get_method;
/*spl_handlers_dual_it.call_method = spl_dual_it_call_method;*/
spl_handlers_dual_it.clone_obj = NULL;
spl_handlers_dual_it.dtor_obj = spl_dual_it_dtor;
spl_handlers_dual_it.free_obj = spl_dual_it_free_storage;

View file

@ -50,7 +50,13 @@ ZEND_END_ARG_INFO()
ZEND_FUNCTION(zend_test_func)
{
/* dummy */
RETVAL_STR_COPY(EX(func)->common.function_name);
/* Cleanup trampoline */
ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
zend_string_release(EX(func)->common.function_name);
zend_free_trampoline(EX(func));
EX(func) = NULL;
}
ZEND_FUNCTION(zend_test_array_return)
@ -144,41 +150,45 @@ static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */
/* }}} */
static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ {
zend_internal_function *fptr = emalloc(sizeof(zend_internal_function));
fptr->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY;
zend_internal_function *fptr;
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
fptr = &EG(trampoline);
} else {
fptr = emalloc(sizeof(zend_internal_function));
}
memset(fptr, 0, sizeof(zend_internal_function));
fptr->type = ZEND_INTERNAL_FUNCTION;
fptr->num_args = 1;
fptr->arg_info = NULL;
fptr->scope = (*object)->ce;
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
fptr->function_name = zend_string_copy(name);
fptr->handler = ZEND_FN(zend_test_func);
zend_set_function_arg_flags((zend_function*)fptr);
return (zend_function*)fptr;
}
/* }}} */
static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name) /* {{{ */ {
zend_internal_function *fptr = emalloc(sizeof(zend_internal_function));
fptr->type = ZEND_OVERLOADED_FUNCTION;
zend_internal_function *fptr;
if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
fptr = &EG(trampoline);
} else {
fptr = emalloc(sizeof(zend_internal_function));
}
memset(fptr, 0, sizeof(zend_internal_function));
fptr->type = ZEND_INTERNAL_FUNCTION;
fptr->num_args = 1;
fptr->arg_info = NULL;
fptr->scope = ce;
fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC;
fptr->function_name = name;
fptr->function_name = zend_string_copy(name);
fptr->handler = ZEND_FN(zend_test_func);
zend_set_function_arg_flags((zend_function*)fptr);
return (zend_function*)fptr;
}
/* }}} */
static int zend_test_class_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ {
RETVAL_STR(zend_string_copy(method));
return 0;
}
/* }}} */
static ZEND_METHOD(_ZendTestTrait, testMethod) /* {{{ */ {
RETURN_TRUE;
}
@ -239,7 +249,6 @@ PHP_MINIT_FUNCTION(zend_test)
memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
zend_test_class_handlers.get_method = zend_test_class_method_get;
zend_test_class_handlers.call_method = zend_test_class_call_method;
INIT_CLASS_ENTRY(class_entry, "_ZendTestTrait", zend_test_trait_methods);
zend_test_trait = zend_register_internal_class(&class_entry);