--- /dev/null
+--TEST--
+Bug #42802 (Namespace not supported in typehints)
+--FILE--
+<?php
+namespace foo;
+
+class bar {
+}
+
+function test1(bar $bar) {
+ echo "ok\n";
+}
+
+function test2(foo::bar $bar) {
+ echo "ok\n";
+}
+function test3(::foo::bar $bar) {
+ echo "ok\n";
+}
+function test4(::Exception $e) {
+ echo "ok\n";
+}
+function test5(Exception $e) {
+ echo "ok\n";
+}
+function test6(::bar $bar) {
+ echo "bug\n";
+}
+
+$x = new bar();
+$y = new Exception();
+test1($x);
+test2($x);
+test3($x);
+test4($y);
+test5($y);
+test6($x);
+--EXPECTF--
+ok
+ok
+ok
+ok
+ok
+
+Catchable fatal error: Argument 1 passed to foo::test6() must be an instance of bar, instance of foo::bar given, called in %sbug42802.php on line 23
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC);
ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC);
+void zend_resolve_class_name(znode *class_name, ulong *fetch_type, int check_ns_name TSRMLS_DC);
+
#ifndef ZTS
ZEND_API zend_compiler_globals compiler_globals;
ZEND_API zend_executor_globals executor_globals;
if (class_type->op_type != IS_UNUSED) {
cur_arg_info->allow_null = 0;
if (Z_TYPE(class_type->u.constant) == IS_STRING || Z_TYPE(class_type->u.constant) == IS_UNICODE) {
+ zend_resolve_class_name(class_type, &opline->extended_value, 1 TSRMLS_CC);
cur_arg_info->class_name = Z_UNIVAL(class_type->u.constant);
cur_arg_info->class_name_len = Z_UNILEN(class_type->u.constant);
if (op == ZEND_RECV_INIT) {
}
/* }}} */
-static inline char * zend_verify_arg_class_kind(zend_arg_info *cur_arg_info, zstr *class_name, zend_class_entry **pce TSRMLS_DC) /* {{{ */
+static inline char * zend_verify_arg_class_kind(zend_arg_info *cur_arg_info, ulong fetch_type, zstr *class_name, zend_class_entry **pce TSRMLS_DC) /* {{{ */
{
- *pce = zend_u_fetch_class(UG(unicode) ? IS_UNICODE : IS_STRING, cur_arg_info->class_name, cur_arg_info->class_name_len, (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
+ *pce = zend_u_fetch_class(UG(unicode) ? IS_UNICODE : IS_STRING, cur_arg_info->class_name, cur_arg_info->class_name_len, (fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
*class_name = (*pce) ? (*pce)->name: cur_arg_info->class_name;
if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
}
/* }}} */
-static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg TSRMLS_DC) /* {{{ */
+static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type TSRMLS_DC) /* {{{ */
{
zend_arg_info *cur_arg_info;
char *need_msg;
zstr class_name;
if (!arg) {
- need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
+ need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "none", EMPTY_ZSTR TSRMLS_CC);
}
if (Z_TYPE_P(arg) == IS_OBJECT) {
- need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
+ need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
return zend_verify_arg_error(zf, arg_num, cur_arg_info, 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) {
- need_msg = zend_verify_arg_class_kind(cur_arg_info, &class_name, &ce TSRMLS_CC);
+ need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, zend_zval_type_name(arg), EMPTY_ZSTR TSRMLS_CC);
}
} else if (cur_arg_info->array_type_hint) {
optional_class_type:
- /* empty */ { $$.op_type = IS_UNUSED; }
- | T_STRING { $$ = $1; }
- | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_NULL;}
+ /* empty */ { $$.op_type = IS_UNUSED; }
+ | fully_qualified_class_name { $$ = $1; }
+ | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_NULL;}
;
arg_count = (ulong)(zend_uintptr_t) *p;
while (arg_count>0) {
- zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count) TSRMLS_CC);
+ zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count), 0 TSRMLS_CC);
arg_count--;
}
}
zstr class_name = get_active_class_name(&space TSRMLS_CC);
zend_execute_data *ptr = EX(prev_execute_data);
- if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC)) {
+ if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
if(ptr && ptr->op_array) {
zend_error(E_WARNING, "Missing argument %ld for %v%s%v(), called in %s on line %d and defined", Z_LVAL(opline->op1.u.constant), class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno);
} else {
zend_free_op free_res;
zval **var_ptr;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
if (PZVAL_IS_REF(*param)) {
zend_assign_to_variable_reference(var_ptr, param TSRMLS_CC);
param = NULL;
assignment_value = &opline->op2.u.constant;
}
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
zend_assign_to_variable(NULL, &opline->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC);
} else {
zval **var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
assignment_value = *param;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
if (PZVAL_IS_REF(assignment_value)) {
zend_assign_to_variable_reference(var_ptr, param TSRMLS_CC);
} else {
arg_count = (ulong)(zend_uintptr_t) *p;
while (arg_count>0) {
- zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count) TSRMLS_CC);
+ zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count), 0 TSRMLS_CC);
arg_count--;
}
}
zstr class_name = get_active_class_name(&space TSRMLS_CC);
zend_execute_data *ptr = EX(prev_execute_data);
- if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL TSRMLS_CC)) {
+ if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) {
if(ptr && ptr->op_array) {
zend_error(E_WARNING, "Missing argument %ld for %v%s%v(), called in %s on line %d and defined", Z_LVAL(opline->op1.u.constant), class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno);
} else {
zend_free_op free_res;
zval **var_ptr;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
if (PZVAL_IS_REF(*param)) {
zend_assign_to_variable_reference(var_ptr, param TSRMLS_CC);
param = NULL;
assignment_value = &opline->op2.u.constant;
}
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
zend_assign_to_variable(NULL, &opline->result, NULL, assignment_value, IS_VAR, EX(Ts) TSRMLS_CC);
} else {
zval **var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W);
assignment_value = *param;
- zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value TSRMLS_CC);
+ zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC);
if (PZVAL_IS_REF(assignment_value)) {
zend_assign_to_variable_reference(var_ptr, param TSRMLS_CC);
} else {