Browse Source

ntroduce infrastructure for supplying information about arguments,

including:

- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance

Both user and builtin functions share the same data structures.

To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:

ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
    ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
    ZEND_ARG_PASS_INFO(0)
    ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();

and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.

The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.

The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
PEAR_1_4DEV
Zeev Suraski 23 years ago
parent
commit
f8bbafd604
  1. 17
      Zend/zend.h
  2. 11
      Zend/zend_API.c
  3. 40
      Zend/zend_API.h
  4. 31
      Zend/zend_builtin_functions.c
  5. 104
      Zend/zend_compile.c
  6. 55
      Zend/zend_compile.h
  7. 108
      Zend/zend_execute.c
  8. 16
      Zend/zend_execute_API.c
  9. 22
      Zend/zend_language_parser.y
  10. 10
      Zend/zend_modules.h
  11. 3
      Zend/zend_object_handlers.c
  12. 14
      Zend/zend_opcode.c
  13. 2
      Zend/zend_reflection_api.c
  14. 2
      ext/reflection/php_reflection.c

17
Zend/zend.h

@ -262,15 +262,6 @@ struct _zval_struct {
zend_uchar is_ref;
};
struct _zend_op_array;
typedef struct _zend_function_entry {
char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
unsigned char *func_arg_types;
} zend_function_entry;
typedef struct _zend_property_reference {
int type; /* read, write or r/w */
zval *object;
@ -306,7 +297,7 @@ struct _zend_class_entry {
HashTable properties_info;
HashTable *static_members;
HashTable constants_table;
zend_function_entry *builtin_functions;
struct _zend_function_entry *builtin_functions;
union _zend_function *constructor;
union _zend_function *destructor;
@ -397,12 +388,6 @@ typedef int (*zend_write_func_t)(const char *str, uint str_length);
#define OE_IS_METHOD (1<<2)
/* Argument passing types */
#define BYREF_NONE 0
#define BYREF_FORCE 1
#define BYREF_ALLOW 2
#define BYREF_FORCE_REST 3
int zend_startup(zend_utility_functions *utility_functions, char **extensions, int start_builtin_functions);
void zend_shutdown(TSRMLS_D);
void zend_register_standard_ini_entries(TSRMLS_D);

11
Zend/zend_API.c

@ -1158,11 +1158,20 @@ int zend_register_functions(zend_class_entry *scope, zend_function_entry *functi
while (ptr->fname) {
internal_function->handler = ptr->handler;
internal_function->arg_types = ptr->func_arg_types;
internal_function->function_name = ptr->fname;
internal_function->scope = scope;
internal_function->fn_flags = ZEND_ACC_PUBLIC;
internal_function->prototype = NULL;
if (ptr->arg_info) {
internal_function->arg_info = ptr->arg_info+1;
internal_function->num_args = ptr->num_args;
internal_function->pass_rest_by_reference = ptr->arg_info[0].pass_by_reference;
} else {
internal_function->arg_info = NULL;
internal_function->num_args = 0;
internal_function->pass_rest_by_reference = 0;
}
internal_function->fn_flags = ptr->flags;
if (!internal_function->handler) {
zend_error(error_type, "Null function defined as active function");
zend_unregister_functions(functions, count, target_function_table TSRMLS_CC);

40
Zend/zend_API.h

@ -32,16 +32,32 @@
BEGIN_EXTERN_C()
#define ZEND_FN(name) zif_##name
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_METHOD(class, name) ZEND_NAMED_FUNCTION(ZEND_FN(class##_##name))
#define ZEND_NAMED_FE(zend_name, name, arg_types) { #zend_name, name, arg_types },
#define ZEND_FE(name, arg_types) ZEND_NAMED_FE(name, ZEND_FN(name), arg_types)
#define ZEND_FALIAS(name, alias, arg_types) ZEND_NAMED_FE(name, ZEND_FN(alias), arg_types)
#define ZEND_STATIC_FE(name, impl_name, arg_types) { name, impl_name, arg_types },
#define ZEND_ME(class, name, arg_types) ZEND_NAMED_FE(name, ZEND_FN(class##_##name), arg_types)
typedef struct _zend_function_entry {
char *fname;
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
struct _zend_arg_info *arg_info;
zend_uint num_args;
zend_uint flags;
} zend_function_entry;
#define ZEND_FN(name) zif_##name
#define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS)
#define ZEND_FUNCTION(name) ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_FN(classname##_##name))
#define ZEND_NAMED_FE(zend_name, name, arg_info) { #zend_name, name, arg_info, sizeof(arg_info)/sizeof(struct _zend_arg_info)-1, 0 },
#define ZEND_FE(name, arg_info) ZEND_NAMED_FE(name, ZEND_FN(name), arg_info)
#define ZEND_FALIAS(name, alias, arg_info) ZEND_NAMED_FE(name, ZEND_FN(alias), arg_info)
#define ZEND_ME(classname, name, arg_info, flags) { #name, ZEND_FN(classname##_##name), arg_info, sizeof(arg_info)/sizeof(struct _zend_arg_info)-1, flags },
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref },
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, pass_by_ref },
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, allow_null, pass_by_ref },
#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) \
zend_arg_info name[] = { \
ZEND_ARG_PASS_INFO(pass_rest_by_reference)
#define ZEND_END_ARG_INFO() };
/* Name macros */
#define ZEND_MODULE_STARTUP_N(module) zm_startup_##module
@ -249,9 +265,9 @@ ZEND_API int add_property_zval_ex(zval *arg, char *key, uint key_len, zval *valu
#define add_property_stringl(__arg, __key, __str, __length, __duplicate) add_property_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate TSRMLS_CC)
#define add_property_zval(__arg, __key, __value) add_property_zval_ex(__arg, __key, strlen(__key)+1, __value TSRMLS_CC)
ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC);
ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC);
ZEND_API int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC);
ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC);
ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC);
ZEND_API int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC);
ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length,
zend_bool is_ref, int num_symbol_tables, ...);

31
Zend/zend_builtin_functions.c

@ -80,9 +80,33 @@ static ZEND_FUNCTION(zend_thread_id);
#endif
#endif
ZEND_API unsigned char first_arg_force_ref[] = { 1, BYREF_FORCE };
ZEND_API unsigned char second_arg_force_ref[] = { 2, BYREF_NONE, BYREF_FORCE };
ZEND_API unsigned char third_arg_force_ref[] = { 3, BYREF_NONE, BYREF_NONE, BYREF_FORCE };
ZEND_API
ZEND_BEGIN_ARG_INFO(first_arg_force_ref, 0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
ZEND_API
ZEND_BEGIN_ARG_INFO(second_arg_force_ref, 0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
ZEND_API
ZEND_BEGIN_ARG_INFO(third_arg_force_ref, 0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
ZEND_API
ZEND_BEGIN_ARG_INFO(fourth_arg_force_ref, 0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
static zend_function_entry builtin_functions[] = {
ZEND_FE(zend_version, NULL)
@ -1712,6 +1736,7 @@ ZEND_FUNCTION(get_extension_funcs)
}
/* }}} */
/*
* Local variables:
* tab-width: 4

104
Zend/zend_compile.c

@ -930,7 +930,6 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
op_array.function_name = name;
op_array.arg_types = NULL;
op_array.return_reference = return_reference;
op_array.fn_flags = fn_flags;
@ -1048,10 +1047,12 @@ void zend_do_end_function_declaration(znode *function_token TSRMLS_DC)
}
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, zend_uchar pass_type TSRMLS_DC)
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_uchar pass_by_reference TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
zend_arg_info *cur_arg_info;
CG(active_op_array)->num_args++;
opline->opcode = op;
opline->result = *var;
opline->op1 = *offset;
@ -1060,33 +1061,20 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia
} else {
SET_UNUSED(opline->op2);
}
if (!CG(active_op_array)->arg_types) {
if (pass_type==BYREF_FORCE) {
int i;
CG(active_op_array)->arg_types = (unsigned char *) emalloc(sizeof(unsigned char)*(offset->u.constant.value.lval+1));
for (i=1; i<offset->u.constant.value.lval; i++) {
CG(active_op_array)->arg_types[i] = BYREF_NONE;
}
CG(active_op_array)->arg_types[0]=(unsigned char) offset->u.constant.value.lval;
CG(active_op_array)->arg_types[offset->u.constant.value.lval] = pass_type;
}
} else {
CG(active_op_array)->arg_types = (unsigned char *) erealloc(CG(active_op_array)->arg_types, sizeof(unsigned char)*(offset->u.constant.value.lval+1));
CG(active_op_array)->arg_types[0]=(unsigned char) offset->u.constant.value.lval;
CG(active_op_array)->arg_types[offset->u.constant.value.lval] = pass_type;
}
CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
cur_arg_info->name = estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len);
cur_arg_info->name_len = varname->u.constant.value.str.len;
cur_arg_info->allow_null = 1;
cur_arg_info->pass_by_reference = pass_by_reference;
if (class_type->op_type != IS_UNUSED) {
znode passed_var = opline->result;
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_VERIFY_INSTANCEOF;
opline->op1 = *class_type;
opline->op2 = passed_var;
opline->extended_value = offset->u.constant.value.lval;
cur_arg_info->class_name = class_type->u.constant.value.str.val;
cur_arg_info->class_name_len = class_type->u.constant.value.str.len;
zend_str_tolower(cur_arg_info->class_name, cur_arg_info->class_name_len);
} else {
cur_arg_info->class_name = NULL;
cur_arg_info->class_name_len = 0;
opline->result.u.EA.type |= EXT_TYPE_UNUSED;
}
}
@ -1296,12 +1284,10 @@ void zend_do_end_function_call(znode *function_name, znode *result, znode *argum
void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC)
{
zend_op *opline;
unsigned char *arg_types;
int original_op=op;
zend_function **function_ptr_ptr, *function_ptr;
int send_by_reference;
zend_stack_top(&CG(function_call_stack), (void **) &function_ptr_ptr);
function_ptr = *function_ptr_ptr;
@ -1318,14 +1304,11 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC)
}
if (function_ptr) {
arg_types = function_ptr->common.arg_types;
send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset) ? ZEND_ARG_SEND_BY_REF : 0;
} else {
arg_types = NULL;
send_by_reference = 0;
}
send_by_reference = ARG_SHOULD_BE_SENT_BY_REF(offset, 1, arg_types)?ZEND_ARG_SEND_BY_REF:0;
if (op == ZEND_SEND_VAR && zend_is_function_or_method_call(param)) {
/* Method call */
op = ZEND_SEND_VAR_NO_REF;
@ -1333,7 +1316,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC)
op = ZEND_SEND_VAR_NO_REF;
}
if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference == ZEND_ARG_SEND_BY_REF) {
if (op!=ZEND_SEND_VAR_NO_REF && send_by_reference==ZEND_ARG_SEND_BY_REF) {
/* change to passing by reference */
switch (param->op_type) {
case IS_VAR:
@ -1611,63 +1594,26 @@ static void do_inherit_method(zend_function *function)
static zend_bool zend_do_perform_implementation_check(zend_function *fe)
{
zend_op *op, *proto_op;
zend_uint i;
if (!fe->common.prototype) {
return 1;
}
if ((fe->common.arg_types && !fe->common.prototype->common.arg_types)
|| (!fe->common.arg_types && fe->common.prototype->common.arg_types)) {
if (fe->common.num_args != fe->common.prototype->common.num_args
|| fe->common.pass_rest_by_reference != fe->common.prototype->common.pass_rest_by_reference) {
return 0;
}
if (fe->common.arg_types) {
if (fe->common.arg_types[0] != fe->common.prototype->common.arg_types[0]) {
for (i=0; i< fe->common.num_args; i++) {
if (strcmp(fe->common.arg_info[i].class_name, fe->common.prototype->common.arg_info[i].class_name)!=0) {
return 0;
}
if (memcmp(fe->common.arg_types+1, fe->common.prototype->common.arg_types+1, fe->common.arg_types[0]*sizeof(zend_uchar)) != 0) {
if (fe->common.arg_info[i].pass_by_reference != fe->common.prototype->common.arg_info[i].pass_by_reference) {
return 0;
}
}
if (fe->common.prototype->type == ZEND_INTERNAL_FUNCTION) {
return 1; /* nothing further we can do here */
}
op = fe->op_array.opcodes;
proto_op = fe->common.prototype->op_array.opcodes;
/* Make sure that the implementation has all of the arguments of the interface */
while (proto_op->opcode != ZEND_RAISE_ABSTRACT_ERROR) {
if (proto_op->opcode != op->opcode) {
return 0;
}
switch (proto_op->opcode) {
case ZEND_FETCH_CLASS:
if (zend_binary_zval_strcasecmp(&op->op2.u.constant, &proto_op->op2.u.constant)!=0) {
return 0;
}
break;
}
proto_op++;
op++;
}
/* Make sure that the implementation doesn't receive more arguments than the interface */
while (1) {
switch (op->opcode) {
case ZEND_FETCH_CLASS:
case ZEND_FETCH_W:
op++;
break;
case ZEND_RECV:
case ZEND_RECV_INIT:
return 0;
default:
return 1;
}
}
return 1;
}

55
Zend/zend_compile.h

@ -121,14 +121,25 @@ typedef struct _zend_property_info {
} zend_property_info;
typedef struct _zend_arg_info {
char *name;
zend_uint name_len;
char *class_name;
zend_uint class_name_len;
zend_bool allow_null;
zend_bool pass_by_reference;
} zend_arg_info;
struct _zend_op_array {
/* Common elements */
zend_uchar type;
zend_uchar *arg_types;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
/* END of common elements */
zend_uint *refcount;
@ -165,11 +176,13 @@ struct _zend_op_array {
typedef struct _zend_internal_function {
/* Common elements */
zend_uchar type;
zend_uchar *arg_types;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
/* END of common elements */
void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
@ -182,11 +195,13 @@ typedef union _zend_function {
struct {
zend_uchar type; /* never used */
zend_uchar *arg_types;
char *function_name;
zend_class_entry *scope;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
} common;
zend_op_array op_array;
@ -320,7 +335,7 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);
int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, zend_uchar pass_type TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, znode *class_type, znode *varname, zend_bool pass_by_reference TSRMLS_DC);
int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC);
@ -653,7 +668,6 @@ int zendlex(znode *zendlval TSRMLS_DC);
#define ZEND_ADD_INTERFACE 144
#define ZEND_VERIFY_INSTANCEOF 145
#define ZEND_VERIFY_ABSTRACT_CLASS 146
#define ZEND_ASSIGN_DIM 147
@ -751,23 +765,24 @@ int zendlex(znode *zendlval TSRMLS_DC);
}
/* Lost In Stupid Parentheses */
#define ARG_SHOULD_BE_SENT_BY_REF(offset, conduct_check, arg_types) \
( \
conduct_check \
&& arg_types \
&& \
( \
( \
offset<=arg_types[0] \
&& arg_types[offset]==BYREF_FORCE \
) \
|| ( \
offset>=arg_types[0] \
&& arg_types[arg_types[0]]==BYREF_FORCE_REST \
) \
) \
#define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
( \
zf \
&& ((zend_function *) zf)->common.arg_info \
&& \
( \
( \
arg_num<=((zend_function *) zf)->common.num_args \
&& ((zend_function *) zf)->common.arg_info[arg_num-1].pass_by_reference \
) \
|| ( \
arg_num>((zend_function *) zf)->common.num_args \
&& ((zend_function *) zf)->common.pass_rest_by_reference \
) \
) \
)
#define ZEND_RETURN_VAL 0
#define ZEND_RETURN_REF 1

108
Zend/zend_execute.c

@ -281,6 +281,49 @@ static inline zval *get_obj_zval_ptr(znode *op, temp_variable *Ts, zval **freeop
return get_zval_ptr(op, Ts, freeop, type);
}
static inline void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg TSRMLS_DC)
{
zend_arg_info *cur_arg_info;
if (!zf->common.arg_info
|| arg_num>zf->common.num_args) {
return;
}
cur_arg_info = &zf->common.arg_info[arg_num-1];
if (cur_arg_info->class_name) {
if (!arg) {
zend_error(E_ERROR, "Argument %d must be an object of class %s", arg_num, cur_arg_info->class_name);
}
switch (Z_TYPE_P(arg)) {
case IS_NULL:
if (!cur_arg_info->allow_null) {
zend_error(E_ERROR, "Argument %d must not be null", arg_num);
}
break;
case IS_OBJECT: {
zend_class_entry *ce = zend_fetch_class(cur_arg_info->class_name, cur_arg_info->class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
if (!instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
char *error_msg;
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
error_msg = "implement interface";
} else {
error_msg = "be an instance of";
}
zend_error(E_ERROR, "Argument %d must %s %s", arg_num, error_msg, ce->name);
}
}
break;
default:
zend_error(E_ERROR, "Argument %d must be an object of class %s", arg_num, cur_arg_info->class_name);
break;
}
}
}
static inline void zend_assign_to_object(znode *result, zval **object_ptr, znode *op2, znode *value_op, temp_variable *Ts, int opcode TSRMLS_DC)
{
zval *object;
@ -1784,7 +1827,7 @@ int zend_fetch_rw_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_fetch_func_arg_handler(ZEND_OPCODE_HANDLER_ARGS)
{
if (ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->extended_value, EX(fbc), EX(fbc)->common.arg_types)) {
if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->extended_value)) {
/* Behave like FETCH_W */
zend_fetch_var_address(EX(opline), EX(Ts), BP_VAR_W TSRMLS_CC);
} else {
@ -1851,7 +1894,7 @@ int zend_fetch_dim_is_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_fetch_dim_func_arg_handler(ZEND_OPCODE_HANDLER_ARGS)
{
if (ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->extended_value, EX(fbc), EX(fbc)->common.arg_types)) {
if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->extended_value)) {
/* Behave like FETCH_DIM_W */
zend_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC);
} else {
@ -1912,7 +1955,7 @@ int zend_fetch_obj_is_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_fetch_obj_func_arg_handler(ZEND_OPCODE_HANDLER_ARGS)
{
if (ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->extended_value, EX(fbc), EX(fbc)->common.arg_types)) {
if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->extended_value)) {
/* Behave like FETCH_OBJ_W */
zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC);
} else {
@ -2453,6 +2496,19 @@ int zend_do_fcall_common_helper(ZEND_OPCODE_HANDLER_ARGS)
ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr);
INIT_ZVAL(*(EX_T(EX(opline)->result.u.var).var.ptr));
if (EX(function_state).function->common.arg_info) {
zend_uint i=0;
zval **p;
ulong arg_count;
p = (zval **) EG(argument_stack).top_element-2;
arg_count = (ulong) *p;
while (arg_count>0) {
zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count) TSRMLS_CC);
arg_count--;
}
}
if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */
((zend_internal_function *) EX(function_state).function)->handler(EX(opline)->extended_value, EX_T(EX(opline)->result.u.var).var.ptr, EX(object), return_value_used TSRMLS_CC);
@ -2702,7 +2758,7 @@ exception_should_be_taken:
int zend_send_val_handler(ZEND_OPCODE_HANDLER_ARGS)
{
if (EX(opline)->extended_value==ZEND_DO_FCALL_BY_NAME
&& ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->op2.u.opline_num, EX(fbc), EX(fbc)->common.arg_types)) {
&& ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->op2.u.opline_num)) {
zend_error(E_ERROR, "Cannot pass parameter %d by reference", EX(opline)->op2.u.opline_num);
}
{
@ -2755,7 +2811,7 @@ int zend_send_var_no_ref_handler(ZEND_OPCODE_HANDLER_ARGS)
if (!(EX(opline)->extended_value & ZEND_ARG_SEND_BY_REF)) {
return zend_send_by_var_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
} else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->op2.u.opline_num, EX(fbc), EX(fbc)->common.arg_types)) {
} else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->op2.u.opline_num)) {
return zend_send_by_var_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
{
@ -2796,7 +2852,7 @@ int zend_send_ref_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_send_var_handler(ZEND_OPCODE_HANDLER_ARGS)
{
if ((EX(opline)->extended_value == ZEND_DO_FCALL_BY_NAME)
&& ARG_SHOULD_BE_SENT_BY_REF(EX(opline)->op2.u.opline_num, EX(fbc), EX(fbc)->common.arg_types)) {
&& ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->op2.u.opline_num)) {
return zend_send_ref_handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
return zend_send_by_var_helper(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@ -2806,16 +2862,21 @@ int zend_send_var_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_recv_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval **param;
zend_uint arg_num = EX(opline)->op1.u.constant.value.lval;
if (zend_ptr_stack_get_arg(EX(opline)->op1.u.constant.value.lval, (void **) &param TSRMLS_CC)==FAILURE) {
if (zend_ptr_stack_get_arg(arg_num, (void **) &param TSRMLS_CC)==FAILURE) {
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC);
zend_error(E_WARNING, "Missing argument %d for %s()\n", EX(opline)->op1.u.constant.value.lval, get_active_function_name(TSRMLS_C));
if (EX(opline)->result.op_type == IS_VAR) {
PZVAL_UNLOCK(*EX_T(EX(opline)->result.u.var).var.ptr_ptr);
}
} else if (PZVAL_IS_REF(*param)) {
zend_assign_to_variable_reference(&EX(opline)->result, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC);
} else {
zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, *param, IS_VAR, EX(Ts) TSRMLS_CC);
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param TSRMLS_CC);
if (PZVAL_IS_REF(*param)) {
zend_assign_to_variable_reference(&EX(opline)->result, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC);
} else {
zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, *param, IS_VAR, EX(Ts) TSRMLS_CC);
}
}
NEXT_OPCODE();
@ -2825,8 +2886,9 @@ int zend_recv_handler(ZEND_OPCODE_HANDLER_ARGS)
int zend_recv_init_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval **param, *assignment_value;
zend_uint arg_num = EX(opline)->op1.u.constant.value.lval;
if (zend_ptr_stack_get_arg(EX(opline)->op1.u.constant.value.lval, (void **) &param TSRMLS_CC)==FAILURE) {
if (zend_ptr_stack_get_arg(arg_num, (void **) &param TSRMLS_CC)==FAILURE) {
if (EX(opline)->op2.u.constant.type == IS_CONSTANT || EX(opline)->op2.u.constant.type==IS_CONSTANT_ARRAY) {
zval *default_value;
@ -2845,9 +2907,11 @@ int zend_recv_init_handler(ZEND_OPCODE_HANDLER_ARGS)
param = NULL;
assignment_value = &EX(opline)->op2.u.constant;
}
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
zend_assign_to_variable(&EX(opline)->result, &EX(opline)->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC);
} else {
assignment_value = *param;
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
if (PZVAL_IS_REF(assignment_value)) {
zend_assign_to_variable_reference(&EX(opline)->result, get_zval_ptr_ptr(&EX(opline)->result, EX(Ts), BP_VAR_W), param, NULL TSRMLS_CC);
} else {
@ -3847,27 +3911,6 @@ int zend_add_interface_handler(ZEND_OPCODE_HANDLER_ARGS)
}
int zend_verify_instanceof_handler(ZEND_OPCODE_HANDLER_ARGS)
{
zval *arg = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R);
zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry;
if ((Z_TYPE_P(arg) != IS_OBJECT)
|| !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
char *error_msg;
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
error_msg = "implement interface";
} else {
error_msg = "be an instance of";
}
zend_error(E_ERROR, "Argument %d must %s %s", EX(opline)->extended_value, error_msg, ce->name);
}
NEXT_OPCODE();
}
#define MAX_ABSTRACT_INFO_CNT 3
#define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
@ -4075,7 +4118,6 @@ void zend_init_opcodes_handlers()
zend_opcode_handlers[ZEND_RAISE_ABSTRACT_ERROR] = zend_raise_abstract_error_handler;
zend_opcode_handlers[ZEND_ADD_INTERFACE] = zend_add_interface_handler;
zend_opcode_handlers[ZEND_VERIFY_INSTANCEOF] = zend_verify_instanceof_handler;
zend_opcode_handlers[ZEND_VERIFY_ABSTRACT_CLASS] = zend_verify_abstract_class_handler;
zend_opcode_handlers[ZEND_ASSIGN_DIM] = zend_assign_dim_handler;

16
Zend/zend_execute_API.c

@ -459,10 +459,10 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC)
}
int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC)
int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint param_count, zval *params[] TSRMLS_DC)
{
zval ***params_array = (zval ***) emalloc(sizeof(zval **)*param_count);
int i;
zend_uint i;
int ex_retval;
zval *local_retval_ptr;
@ -479,16 +479,18 @@ int call_user_function(HashTable *function_table, zval **object_pp, zval *functi
return ex_retval;
}
int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC)
int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC)
{
zend_function *function_pointer = NULL;
return fast_call_user_function(function_table, object_pp, function_name, retval_ptr_ptr, param_count, params, no_separation, symbol_table, &function_pointer TSRMLS_CC);
}
int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC)
int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC)
{
int i;
zend_uint i;
zval **original_return_value;
HashTable *calling_symbol_table;
zend_function_state *original_function_state_ptr;
@ -611,9 +613,7 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
for (i=0; i<param_count; i++) {
zval *param;
if (EX(function_state).function->common.arg_types
&& i<EX(function_state).function->common.arg_types[0]
&& EX(function_state).function->common.arg_types[i+1]==BYREF_FORCE
if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i+1)
&& !PZVAL_IS_REF(*params[i])) {
if ((*params[i])->refcount>1) {
zval *new_zval;

22
Zend/zend_language_parser.y

@ -390,22 +390,22 @@ parameter_list:
non_empty_parameter_list:
optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, BYREF_NONE TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, BYREF_FORCE TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, &$1, BYREF_FORCE TSRMLS_CC); }
| T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$2, BYREF_NONE TSRMLS_CC); }
| optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$4, &$1, BYREF_NONE TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, BYREF_NONE TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, BYREF_FORCE TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$7, &$3, BYREF_FORCE TSRMLS_CC); }
| non_empty_parameter_list ',' T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$4, BYREF_NONE TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$6, &$3, BYREF_NONE TSRMLS_CC); }
optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, &$2, 0 TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, &$3, 1 TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, &$1, &$3, 1 TSRMLS_CC); }
| T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$2, &$3, 0 TSRMLS_CC); }
| optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; $$.u.constant.value.lval=1; $$.u.constant.type=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$4, &$1, &$2, 0 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, &$4, 0 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, &$5, 1 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$7, &$3, &$5, 1 TSRMLS_CC); }
| non_empty_parameter_list ',' T_CONST optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$4, &$5, 0 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; $$.u.constant.value.lval++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$6, &$3, &$4, 0 TSRMLS_CC); }
;
optional_class_type:
/* empty */ { $$.op_type = IS_UNUSED; }
| fully_qualified_class_name { $$ = $1; }
| T_STRING { $$ = $1; }
;

10
Zend/zend_modules.h

@ -31,9 +31,11 @@
#define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC
#define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC
ZEND_API extern unsigned char first_arg_force_ref[];
ZEND_API extern unsigned char second_arg_force_ref[];
ZEND_API extern unsigned char third_arg_force_ref[];
ZEND_API extern struct _zend_arg_info first_arg_force_ref[2];
ZEND_API extern struct _zend_arg_info second_arg_force_ref[3];
ZEND_API extern struct _zend_arg_info third_arg_force_ref[4];
ZEND_API extern struct _zend_arg_info fourth_arg_force_ref[5];
ZEND_API extern struct _zend_arg_info all_args_by_ref[1];
#define ZEND_MODULE_API_NO 20020429
#ifdef ZTS
@ -65,7 +67,7 @@ struct _zend_module_entry {
unsigned char zts;
struct _zend_ini_entry *ini_entry;
char *name;
zend_function_entry *functions;
struct _zend_function_entry *functions;
int (*module_startup_func)(INIT_FUNC_ARGS);
int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);
int (*request_startup_func)(INIT_FUNC_ARGS);

3
Zend/zend_object_handlers.c

@ -617,7 +617,8 @@ static union _zend_function *zend_std_get_method(zval *object, char *method_name
zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
call_user_call->type = ZEND_INTERNAL_FUNCTION;
call_user_call->handler = zend_std_call_user_call;
call_user_call->arg_types = NULL;
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);

14
Zend/zend_opcode.c

@ -77,7 +77,8 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz
op_array->doc_comment = NULL;
op_array->doc_comment_len = 0;
op_array->arg_types = NULL;
op_array->arg_info = NULL;
op_array->num_args = 0;
op_array->scope = NULL;
@ -190,6 +191,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
{
zend_op *opline = op_array->opcodes;
zend_op *end = op_array->opcodes+op_array->last;
zend_uint i;
if (op_array->static_variables) {
zend_hash_destroy(op_array->static_variables);
@ -224,15 +226,19 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
if (op_array->doc_comment) {
efree(op_array->doc_comment);
}
if (op_array->arg_types) {
efree(op_array->arg_types);
}
if (op_array->brk_cont_array) {
efree(op_array->brk_cont_array);
}
if (op_array->done_pass_two) {
zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
}
if (op_array->arg_info) {
for (i=0; i<op_array->num_args; i++) {
efree(op_array->arg_info[i].name);
efree(op_array->arg_info[i].class_name);
}
efree(op_array->arg_info);
}
}

2
Zend/zend_reflection_api.c

@ -1621,7 +1621,7 @@ ZEND_FUNCTION(reflection_class_getinterfaces)
array_init(return_value);
if (ce->num_interfaces) {
int i;
zend_uint i;
for (i=0; i < ce->num_interfaces; i++) {
zval *interface;

2
ext/reflection/php_reflection.c

@ -1621,7 +1621,7 @@ ZEND_FUNCTION(reflection_class_getinterfaces)
array_init(return_value);
if (ce->num_interfaces) {
int i;
zend_uint i;
for (i=0; i < ce->num_interfaces; i++) {
zval *interface;

Loading…
Cancel
Save