Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added array type hinting. (This patch requires full re-make)

  • Loading branch information...
commit 1a7234132850e750a167cc6195498be895b4f5aa 1 parent 3453cf6
Dmitry Stogov authored
View
1  NEWS
@@ -1,6 +1,7 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2004, PHP 5.1.0
+- Added array type hinting. (Dmitry)
- Removed php_check_syntax() function which never worked properly. (Ilia)
- Removed garbage manager in Zend Engine which results in more aggressive
freeing of data. (Dmitry, Andi)
View
15 Zend/tests/array_type_hint_001.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Array type hint
+--FILE--
+<?php
+function foo(array $a) {
+ echo count($a)."\n";
+}
+
+foo(array(1,2,3));
+foo(123);
+?>
+--EXPECTF--
+3
+
+Fatal error: Argument 1 must be an array in %sarray_type_hint_001.php on line 2
View
9 Zend/zend_API.h
@@ -57,12 +57,13 @@ typedef struct _zend_function_entry {
ZEND_FENTRY(name, ZEND_FN(classname##_##alias), arg_info, flags)
#define ZEND_ME_MAPPING(name, func_name, arg_types) ZEND_NAMED_FE(name, ZEND_FN(func_name), arg_types)
-#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 },
-#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 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, allow_null, pass_by_ref, 0, 0 },
+#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_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
zend_arg_info name[] = { \
- { NULL, 0, NULL, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
+ { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },
#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) \
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_REFERENCE_AGNOSTIC, -1)
#define ZEND_END_ARG_INFO() };
View
15 Zend/zend_compile.c
@@ -1221,12 +1221,19 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia
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->allow_null = 1;
cur_arg_info->pass_by_reference = pass_by_reference;
if (class_type->op_type != IS_UNUSED) {
- 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;
+ if (class_type->u.constant.type == IS_STRING) {
+ 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;
+ } else {
+ cur_arg_info->array_type_hint = 1;
+ cur_arg_info->class_name = NULL;
+ cur_arg_info->class_name_len = 0;
+ }
cur_arg_info->allow_null = 0;
} else {
cur_arg_info->class_name = NULL;
@@ -1844,6 +1851,10 @@ static zend_bool zend_do_perform_implementation_check(zend_function *fe, zend_fu
&& strcmp(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)!=0) {
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 */
+ return 0;
+ }
if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
return 0;
}
View
1  Zend/zend_compile.h
@@ -148,6 +148,7 @@ typedef struct _zend_arg_info {
zend_uint name_len;
char *class_name;
zend_uint class_name_len;
+ zend_bool array_type_hint;
zend_bool allow_null;
zend_bool pass_by_reference;
zend_bool return_reference;
View
18 Zend/zend_execute.c
@@ -602,7 +602,23 @@ static inline void zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zv
zend_error_noreturn(E_ERROR, "Argument %d must be an object of class %s", arg_num, cur_arg_info->class_name);
break;
}
- }
+ } else if (cur_arg_info->array_type_hint) {
+ if (!arg) {
+ zend_error_noreturn(E_ERROR, "Argument %d must be an array", arg_num);
+ }
+ switch (Z_TYPE_P(arg)) {
+ case IS_NULL:
+ if (!cur_arg_info->allow_null) {
+ zend_error_noreturn(E_ERROR, "Argument %d must not be null", arg_num);
+ }
+ break;
+ case IS_ARRAY:
+ break;
+ default:
+ zend_error_noreturn(E_ERROR, "Argument %d must be an array", arg_num);
+ break;
+ }
+ }
}
View
1  Zend/zend_language_parser.y
@@ -434,6 +434,7 @@ non_empty_parameter_list:
optional_class_type:
/* empty */ { $$.op_type = IS_UNUSED; }
| T_STRING { $$ = $1; }
+ | T_ARRAY { $$.op_type = IS_CONST; $$.u.constant.type=IS_NULL;}
;
View
20 Zend/zend_reflection_api.c
@@ -519,6 +519,11 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
if (arg_info->allow_null) {
string_printf(str, "or NULL ");
}
+ } else if (arg_info->array_type_hint) {
+ string_printf(str, "array ");
+ if (arg_info->allow_null) {
+ string_printf(str, "or NULL ");
+ }
}
if (arg_info->pass_by_reference) {
string_write(str, "&", sizeof("&")-1);
@@ -1716,6 +1721,20 @@ ZEND_METHOD(reflection_parameter, getClass)
}
/* }}} */
+/* {{{ proto public bool ReflectionParameter::isArray()
+ Returns whether parameter MUST be an array */
+ZEND_METHOD(reflection_parameter, isArray)
+{
+ reflection_object *intern;
+ parameter_reference *param;
+
+ METHOD_NOTSTATIC_NUMPARAMS(0);
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->array_type_hint);
+}
+/* }}} */
+
/* {{{ proto public bool ReflectionParameter::allowsNull()
Returns whether NULL is allowed as this parameters's value */
ZEND_METHOD(reflection_parameter, allowsNull)
@@ -3852,6 +3871,7 @@ static zend_function_entry reflection_parameter_functions[] = {
ZEND_ME(reflection_parameter, getName, NULL, 0)
ZEND_ME(reflection_parameter, isPassedByReference, NULL, 0)
ZEND_ME(reflection_parameter, getClass, NULL, 0)
+ ZEND_ME(reflection_parameter, isArray, NULL, 0)
ZEND_ME(reflection_parameter, allowsNull, NULL, 0)
ZEND_ME(reflection_parameter, isOptional, NULL, 0)
ZEND_ME(reflection_parameter, isDefaultValueAvailable, NULL, 0)
View
20 ext/reflection/php_reflection.c
@@ -519,6 +519,11 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
if (arg_info->allow_null) {
string_printf(str, "or NULL ");
}
+ } else if (arg_info->array_type_hint) {
+ string_printf(str, "array ");
+ if (arg_info->allow_null) {
+ string_printf(str, "or NULL ");
+ }
}
if (arg_info->pass_by_reference) {
string_write(str, "&", sizeof("&")-1);
@@ -1716,6 +1721,20 @@ ZEND_METHOD(reflection_parameter, getClass)
}
/* }}} */
+/* {{{ proto public bool ReflectionParameter::isArray()
+ Returns whether parameter MUST be an array */
+ZEND_METHOD(reflection_parameter, isArray)
+{
+ reflection_object *intern;
+ parameter_reference *param;
+
+ METHOD_NOTSTATIC_NUMPARAMS(0);
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->array_type_hint);
+}
+/* }}} */
+
/* {{{ proto public bool ReflectionParameter::allowsNull()
Returns whether NULL is allowed as this parameters's value */
ZEND_METHOD(reflection_parameter, allowsNull)
@@ -3852,6 +3871,7 @@ static zend_function_entry reflection_parameter_functions[] = {
ZEND_ME(reflection_parameter, getName, NULL, 0)
ZEND_ME(reflection_parameter, isPassedByReference, NULL, 0)
ZEND_ME(reflection_parameter, getClass, NULL, 0)
+ ZEND_ME(reflection_parameter, isArray, NULL, 0)
ZEND_ME(reflection_parameter, allowsNull, NULL, 0)
ZEND_ME(reflection_parameter, isOptional, NULL, 0)
ZEND_ME(reflection_parameter, isDefaultValueAvailable, NULL, 0)
Please sign in to comment.
Something went wrong with that request. Please try again.