if (class_type->u.constant.type == IS_ARRAY) {
cur_arg_info->type_hint = IS_ARRAY;
if (op == ZEND_RECV_INIT) {
- if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) {
+ if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
cur_arg_info->allow_null = 1;
+ } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+ /* delay constant resolution and check to run-time */
+ cur_arg_info->allow_null = 0;
} else if (Z_TYPE(initialization->u.constant) != IS_ARRAY) {
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL");
}
} else if (class_type->u.constant.type == IS_CALLABLE) {
cur_arg_info->type_hint = IS_CALLABLE;
if (op == ZEND_RECV_INIT) {
- if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) {
+ if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
cur_arg_info->allow_null = 1;
+ } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+ /* delay constant resolution and check to run-time */
+ cur_arg_info->allow_null = 0;
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with callable type hint can only be NULL");
}
cur_arg_info->class_name = Z_STRVAL(class_type->u.constant);
cur_arg_info->class_name_len = Z_STRLEN(class_type->u.constant);
if (op == ZEND_RECV_INIT) {
- if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL")) || Z_TYPE(initialization->u.constant) == IS_CONSTANT_AST) {
+ if (Z_TYPE(initialization->u.constant) == IS_NULL || (Z_TYPE(initialization->u.constant) == IS_CONSTANT && !strcasecmp(Z_STRVAL(initialization->u.constant), "NULL"))) {
cur_arg_info->allow_null = 1;
+ } else if (IS_CONSTANT_TYPE(Z_TYPE(initialization->u.constant))) {
+ /* delay constant resolution and check to run-time */
+ cur_arg_info->allow_null = 0;
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL");
}
return 0;
}
-static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC)
+static int is_null_constant(zval *default_value)
+{
+ if (IS_CONSTANT_TYPE(Z_TYPE_P(default_value))) {
+ zval constant = *default_value;
+ zval *constant_ptr = &constant;
+
+ zval_update_constant(&constant_ptr, 0 TSRMLS_CC);
+ if (Z_TYPE(constant) == IS_NULL) {
+ return 1;
+ }
+ zval_dtor(&constant);
+ }
+ return 0;
+}
+
+static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type, zval *default_value TSRMLS_DC)
{
zend_arg_info *cur_arg_info;
char *need_msg;
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
}
- } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) {
+ } else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value)))) {
need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
}
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
}
- if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
+ if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
}
break;
if (!arg) {
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
}
- if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) {
+ if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) {
return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
}
break;
void **p = EX(function_state).arguments - num_args;
for (i = 0; i < num_args; ++i, ++p) {
- zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC);
+ zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0, NULL TSRMLS_CC);
}
}
SAVE_OPLINE();
if (UNEXPECTED(param == NULL)) {
- if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
+ if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value, NULL TSRMLS_CC)) {
const char *space;
const char *class_name;
zend_execute_data *ptr;
} else {
zval **var_ptr;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value, NULL TSRMLS_CC);
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
Z_DELREF_PP(var_ptr);
*var_ptr = *param;
Z_ADDREF_P(assignment_value);
}
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value, opline->op2.zv TSRMLS_CC);
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
zval_ptr_dtor(var_ptr);
*var_ptr = assignment_value;
for (; arg_num <= arg_count; ++arg_num) {
zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value, NULL TSRMLS_CC);
zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
Z_ADDREF_PP(param);
}
void **p = EX(function_state).arguments - num_args;
for (i = 0; i < num_args; ++i, ++p) {
- zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0 TSRMLS_CC);
+ zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0, NULL TSRMLS_CC);
}
}
SAVE_OPLINE();
if (UNEXPECTED(param == NULL)) {
- if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
+ if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value, NULL TSRMLS_CC)) {
const char *space;
const char *class_name;
zend_execute_data *ptr;
} else {
zval **var_ptr;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value, NULL TSRMLS_CC);
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
Z_DELREF_PP(var_ptr);
*var_ptr = *param;
for (; arg_num <= arg_count; ++arg_num) {
zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value, NULL TSRMLS_CC);
zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
Z_ADDREF_PP(param);
}
Z_ADDREF_P(assignment_value);
}
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value, opline->op2.zv TSRMLS_CC);
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
zval_ptr_dtor(var_ptr);
*var_ptr = assignment_value;