if (ptr->arg_info) {
internal_function->arg_info = ptr->arg_info+1;
internal_function->num_args = ptr->num_args;
+ /* Currently you cannot denote that the function can accept less arguments than num_args */
+ internal_function->required_num_args = ptr->num_args;
internal_function->pass_rest_by_reference = ptr->arg_info[0].pass_by_reference;
internal_function->return_reference = ptr->arg_info[0].return_reference;
} else {
internal_function->arg_info = NULL;
internal_function->num_args = 0;
+ internal_function->required_num_args = 0;
internal_function->pass_rest_by_reference = 0;
internal_function->return_reference = 0;
}
opline->opcode = op;
opline->result = *var;
opline->op1 = *offset;
- if ((op == ZEND_RECV_INIT)) {
+ if (op == ZEND_RECV_INIT) {
+ if ((CG(active_class_entry) && CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)
+ || CG(active_op_array)->fn_flags & ZEND_ACC_ABSTRACT) {
+ CG(active_op_array)->num_args--; /* invalidate the current arg_info entry */
+ zend_error(E_COMPILE_ERROR, "Abstract methods cannot have default values for arguments");
+ }
opline->op2 = *initialization;
} else {
+ CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
SET_UNUSED(opline->op2);
}
CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
static zend_bool zend_do_perform_implementation_check(zend_function *fe)
{
zend_uint i;
+ zend_function *proto = fe->common.prototype;
- if (!fe->common.prototype) {
+ if (!proto) {
return 1;
}
- 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) {
+ /* check number of arguments */
+ if (proto->common.num_args < fe->common.required_num_args
+ || proto->common.num_args > fe->common.num_args) {
+ return 0;
+ }
+
+ if (proto->common.pass_rest_by_reference
+ && !fe->common.pass_rest_by_reference) {
return 0;
}
- if (fe->common.prototype->common.return_reference != ZEND_RETURN_REFERENCE_AGNOSTIC
- && fe->common.return_reference != fe->common.prototype->common.return_reference) {
+ if (proto->common.return_reference != ZEND_RETURN_REFERENCE_AGNOSTIC
+ && fe->common.return_reference != proto->common.return_reference) {
return 0;
}
- for (i=0; i< fe->common.num_args; i++) {
- if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, fe->common.prototype->common.arg_info[i].class_name)) {
+ for (i=0; i < proto->common.num_args; i++) {
+ if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) {
/* Only one has a type hint and the other one doesn't */
return 0;
}
if (fe->common.arg_info[i].class_name
- && strcmp(fe->common.arg_info[i].class_name, fe->common.prototype->common.arg_info[i].class_name)!=0) {
+ && strcmp(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)!=0) {
return 0;
}
- if (fe->common.arg_info[i].pass_by_reference != fe->common.prototype->common.arg_info[i].pass_by_reference) {
+ if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
return 0;
}
}
+
+ if (proto->common.pass_rest_by_reference) {
+ for (i=proto->common.num_args; i < fe->common.num_args; i++) {
+ if (!fe->common.arg_info[i].pass_by_reference) {
+ return 0;
+ }
+ }
+ }
return 1;
}
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
+ zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
+ zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;
zend_uint fn_flags;
union _zend_function *prototype;
zend_uint num_args;
+ zend_uint required_num_args;
zend_arg_info *arg_info;
zend_bool pass_rest_by_reference;
unsigned char return_reference;