Index: Zend/zend.h =================================================================== RCS file: /repository/ZendEngine2/zend.h,v retrieving revision 1.293.2.11.2.9.2.37 diff -u -p -a -d -u -r1.293.2.11.2.9.2.37 zend.h --- Zend/zend.h 17 Jun 2009 08:55:23 -0000 1.293.2.11.2.9.2.37 +++ Zend/zend.h 1 Jul 2009 16:45:02 -0000 @@ -536,6 +536,10 @@ typedef int (*zend_write_func_t)(const c #define IS_RESOURCE 7 #define IS_CONSTANT 8 #define IS_CONSTANT_ARRAY 9 +/* used for type-hinting only */ +#define IS_NUMERIC 10 +#define IS_SCALAR 11 + /* Ugly hack to support constants as static array indices */ #define IS_CONSTANT_TYPE_MASK 0x0f Index: Zend/zend_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_API.c,v retrieving revision 1.296.2.27.2.34.2.64 diff -u -p -a -d -u -r1.296.2.27.2.34.2.64 zend_API.c --- Zend/zend_API.c 4 Jun 2009 18:20:42 -0000 1.296.2.27.2.34.2.64 +++ Zend/zend_API.c 1 Jul 2009 16:45:02 -0000 @@ -213,6 +213,10 @@ ZEND_API char *zend_get_type_by_const(in return "null"; case IS_ARRAY: return "array"; + case IS_SCALAR: + return "scalar"; + case IS_NUMERIC: + return "numeric"; default: return "unknown"; } Index: Zend/zend_API.h =================================================================== RCS file: /repository/ZendEngine2/zend_API.h,v retrieving revision 1.207.2.8.2.8.2.24 diff -u -p -a -d -u -r1.207.2.8.2.8.2.24 zend_API.h --- Zend/zend_API.h 31 Dec 2008 11:15:31 -0000 1.207.2.8.2.8.2.24 +++ Zend/zend_API.h 1 Jul 2009 16:45:02 -0000 @@ -98,8 +98,8 @@ typedef struct _zend_fcall_info_cache { #define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, #define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, 0, allow_null, pass_by_ref, 0, 0 }, -#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, 1, allow_null, pass_by_ref, 0, 0 }, +#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, allow_null, pass_by_ref, 0, 0 }, +#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref, 0, 0 }, #define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \ static const zend_arg_info name[] = { \ { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args }, Index: Zend/zend_compile.c =================================================================== RCS file: /repository/ZendEngine2/zend_compile.c,v retrieving revision 1.647.2.27.2.41.2.109 diff -u -p -a -d -u -r1.647.2.27.2.41.2.109 zend_compile.c --- Zend/zend_compile.c 7 Jun 2009 15:46:51 -0000 1.647.2.27.2.41.2.109 +++ Zend/zend_compile.c 1 Jul 2009 16:45:02 -0000 @@ -1490,7 +1490,7 @@ void zend_do_receive_arg(zend_uchar op, 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->array_type_hint = 0; + cur_arg_info->type_hint = 0; cur_arg_info->allow_null = 1; cur_arg_info->pass_by_reference = pass_by_reference; cur_arg_info->class_name = NULL; @@ -1498,7 +1498,10 @@ void zend_do_receive_arg(zend_uchar op, if (class_type->op_type != IS_UNUSED) { cur_arg_info->allow_null = 0; - if (class_type->u.constant.type == IS_STRING) { + cur_arg_info->type_hint = class_type->u.constant.type; + + switch (class_type->u.constant.type) { + case IS_OBJECT: if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) { zend_resolve_class_name(class_type, &opline->extended_value, 1 TSRMLS_CC); } @@ -1511,10 +1514,9 @@ void zend_do_receive_arg(zend_uchar op, zend_error(E_COMPILE_ERROR, "Default value for parameters with a class type hint can only be NULL"); } } - } else { - cur_arg_info->array_type_hint = 1; - cur_arg_info->class_name = NULL; - cur_arg_info->class_name_len = 0; + break; + + case 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"))) { cur_arg_info->allow_null = 1; @@ -1522,6 +1524,25 @@ void zend_do_receive_arg(zend_uchar op, zend_error(E_COMPILE_ERROR, "Default value for parameters with array type hint can only be an array or NULL"); } } + break; + + /* scalar type hinting */ + case IS_BOOL: + case IS_STRING: + case IS_LONG: + case IS_DOUBLE: + case IS_RESOURCE: + case IS_NUMERIC: + case IS_SCALAR: + if (op == ZEND_RECV_INIT && Z_TYPE(initialization->u.constant) != class_type->u.constant.type && Z_TYPE(initialization->u.constant) != IS_NULL) { + zend_error(E_COMPILE_ERROR, "Default value for parameters with %s type hint can only be %s or NULL", zend_get_type_by_const(class_type->u.constant.type), zend_get_type_by_const(class_type->u.constant.type)); + } else { + cur_arg_info->allow_null = 1; + } + break; + + default: + zend_error(E_COMPILE_ERROR, "Unkown type hint"); } } opline->result.u.EA.type |= EXT_TYPE_UNUSED; @@ -2541,8 +2562,8 @@ static zend_bool zend_do_perform_impleme return 0; } } - if (fe->common.arg_info[i].array_type_hint != proto->common.arg_info[i].array_type_hint) { - /* Only one has an array type hint and the other one doesn't */ + if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) { + /* Incompatible type hint */ return 0; } if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) { Index: Zend/zend_compile.h =================================================================== RCS file: /repository/ZendEngine2/zend_compile.h,v retrieving revision 1.316.2.8.2.12.2.40 diff -u -p -a -d -u -r1.316.2.8.2.12.2.40 zend_compile.h --- Zend/zend_compile.h 5 Jun 2009 23:20:59 -0000 1.316.2.8.2.12.2.40 +++ Zend/zend_compile.h 1 Jul 2009 16:45:02 -0000 @@ -175,7 +175,7 @@ typedef struct _zend_arg_info { zend_uint name_len; const char *class_name; zend_uint class_name_len; - zend_bool array_type_hint; + zend_uint type_hint; zend_bool allow_null; zend_bool pass_by_reference; zend_bool return_reference; Index: Zend/zend_execute.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute.c,v retrieving revision 1.716.2.12.2.24.2.44 diff -u -p -a -d -u -r1.716.2.12.2.24.2.44 zend_execute.c --- Zend/zend_execute.c 4 Jun 2009 18:20:42 -0000 1.716.2.12.2.24.2.44 +++ Zend/zend_execute.c 1 Jul 2009 16:45:02 -0000 @@ -504,12 +504,33 @@ static inline int zend_verify_arg_type(z 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), "" TSRMLS_CC); } - } else if (cur_arg_info->array_type_hint) { + } else if (cur_arg_info->type_hint) { if (!arg) { - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", "none", "" TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be ", zend_get_type_by_const(cur_arg_info->type_hint), "none", "" TSRMLS_CC); } - if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + if (Z_TYPE_P(arg) != cur_arg_info->type_hint && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { + if (cur_arg_info->type_hint == IS_SCALAR) { + switch (Z_TYPE_P(arg)) { + case IS_STRING: + case IS_BOOL: + case IS_LONG: + case IS_DOUBLE: + return 1; + } + } else if (cur_arg_info->type_hint == IS_NUMERIC) { + switch (Z_TYPE_P(arg)) { + case IS_STRING: + if (is_numeric_string(Z_STRVAL_P(arg), Z_STRLEN_P(arg), NULL, NULL, 0)) { + return 1; + } + break; + case IS_BOOL: + case IS_LONG: + case IS_DOUBLE: + return 1; + } + } + return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be ", zend_get_type_by_const(cur_arg_info->type_hint), "", zend_zval_type_name(arg) TSRMLS_CC); } } return 1; Index: Zend/zend_language_parser.y =================================================================== RCS file: /repository/ZendEngine2/zend_language_parser.y,v retrieving revision 1.160.2.4.2.8.2.35 diff -u -p -a -d -u -r1.160.2.4.2.8.2.35 zend_language_parser.y --- Zend/zend_language_parser.y 26 Mar 2009 12:37:17 -0000 1.160.2.4.2.8.2.35 +++ Zend/zend_language_parser.y 1 Jul 2009 16:45:02 -0000 @@ -128,6 +128,13 @@ %token T_DOUBLE_ARROW %token T_LIST %token T_ARRAY +%token T_BOOL_HINT +%token T_STRING_HINT +%token T_INT_HINT +%token T_DOUBLE_HINT +%token T_RESOURCE_HINT +%token T_NUMERIC_HINT +%token T_SCALAR_HINT %token T_CLASS_C %token T_METHOD_C %token T_FUNC_C @@ -463,8 +470,15 @@ non_empty_parameter_list: optional_class_type: /* empty */ { $$.op_type = IS_UNUSED; } - | fully_qualified_class_name { $$ = $1; } - | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_NULL;} + | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_ARRAY; } + | T_BOOL_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_BOOL; } + | T_STRING_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_STRING; } + | T_INT_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_LONG; } + | T_DOUBLE_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_DOUBLE; } + | T_RESOURCE_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_RESOURCE; } + | T_NUMERIC_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_NUMERIC; } + | T_SCALAR_HINT { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_SCALAR; } + | fully_qualified_class_name { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_OBJECT; } ; Index: Zend/zend_language_scanner.l =================================================================== RCS file: /repository/ZendEngine2/zend_language_scanner.l,v retrieving revision 1.131.2.11.2.13.2.40 diff -u -p -a -d -u -r1.131.2.11.2.13.2.40 zend_language_scanner.l --- Zend/zend_language_scanner.l 5 May 2009 01:35:44 -0000 1.131.2.11.2.13.2.40 +++ Zend/zend_language_scanner.l 1 Jul 2009 16:45:02 -0000 @@ -1158,6 +1158,34 @@ NEWLINE ("\r"|"\n"|"\r\n") return T_ARRAY; } +("bool"|"boolean") { + return T_BOOL_HINT; +} + +("string"|"binary"|"unicode") { + return T_STRING_HINT; +} + +("int"|"integer"|"long") { + return T_INT_HINT; +} + +("real"|"double"|"float") { + return T_DOUBLE_HINT; +} + +("resource") { + return T_RESOURCE_HINT; +} + +("numeric") { + return T_NUMERIC_HINT; +} + +("scalar") { + return T_SCALAR_HINT; +} + "++" { return T_INC; } Index: ext/reflection/php_reflection.c =================================================================== RCS file: /repository/php-src/ext/reflection/php_reflection.c,v retrieving revision 1.164.2.33.2.45.2.58 diff -u -p -a -d -r1.164.2.33.2.45.2.58 php_reflection.c --- ext/reflection/php_reflection.c 16 Jun 2009 14:33:33 -0000 1.164.2.33.2.45.2.58 +++ ext/reflection/php_reflection.c 2 Jul 2009 03:13:51 -0000 @@ -676,7 +676,7 @@ static void _parameter_string(string *st if (arg_info->allow_null) { string_printf(str, "or NULL "); } - } else if (arg_info->array_type_hint) { + } else if (arg_info->type_hint == IS_ARRAY) { string_printf(str, "array "); if (arg_info->allow_null) { string_printf(str, "or NULL "); @@ -2270,7 +2270,7 @@ ZEND_METHOD(reflection_parameter, isArra } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->array_type_hint); + RETVAL_BOOL(param->arg_info->type_hint == IS_ARRAY); } /* }}} */ @@ -4496,7 +4496,7 @@ ZEND_METHOD(reflection_property, getValu *return_value= *member_p; zval_copy_ctor(return_value); INIT_PZVAL(return_value); - if (member_p != EG(uninitialized_zval_ptr)) { + if (member_p == EG(uninitialized_zval_ptr)) { zval_add_ref(&member_p); zval_ptr_dtor(&member_p); }