From 34ba797903bd5139a3b812ed6dad50b8bf4569cb Mon Sep 17 00:00:00 2001 From: Olivier Favre Date: Thu, 14 Jun 2012 10:42:48 +0200 Subject: [PATCH 1/2] Permit ZEND_ARG_TYPE_INFO with other types than IS_ARRAY and IS_CALLABLE Zend/zend_execute.c:zend_verify_arg_type() enforces some type hints: - wrong object class (assumes an implied type hint to IS_OBJECT) - not an array - not a callable - disallowed nullness for the previous cases - for any other type hints, raise an error Those hints are used in the Reflection API (currently only in __toString as there is no getter). Zend/zend_API.c:zend_parse_arg_impl() uses a provided format string and performs automatic convertion if possible. The zend_verify_arg_type() function is called by the Zend VM at some low level. As PHP wants more flexibility, it should not enforce type hinting much. Hence, I left the current rules, but removed the last one that raises an error for non object, array or callable types. As a consequence, ARG_INFOs of PHP_FE can now be more precise and helpful. --- Zend/zend_execute.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 205531fd28e53..fec35922e3d9a 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -645,9 +645,6 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC); } break; - - default: - zend_error(E_ERROR, "Unknown typehint"); } } return 1; From 0388e5061055f919ed794afe946d0415a5f0890e Mon Sep 17 00:00:00 2001 From: Olivier Favre Date: Thu, 14 Jun 2012 11:55:07 +0200 Subject: [PATCH 2/2] See #45569 - ReflectionParameter::getTypeHint() function Type hinting is an available information in ReflectionParameter, however it is only used in __toString()! Made that information available through the getTypeHint() function, which returns the string representation of the type hint constant. Turned ReflectionParameter::export() and __construct() to use ZEND_ARG_TYPE_INFO() instead of ZEND_ARG_INFO(), in order to register the actual type hinting. Added a test to ensure getTypeHint() works fine with type hinted function and returns NULL for non type hinted ones. See request #45569, the second part. --- ext/reflection/php_reflection.c | 30 ++++++++++++++++++++----- tests/classes/type_hinting_006.phpt | 35 +++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 tests/classes/type_hinting_006.phpt diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9346587eb7f02..0aabcd5a02607 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2390,6 +2390,25 @@ ZEND_METHOD(reflection_parameter, getClass) } /* }}} */ +/* {{{ proto public string|NULL ReflectionParameter::getTypeHint() + Returns the type hint, or NULL if there is none */ +ZEND_METHOD(reflection_parameter, getTypeHint) +{ + reflection_object *intern; + parameter_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(param); + + if (!param->arg_info->type_hint) { + RETVAL_NULL(); + } else { + RETVAL_STRING(zend_get_type_by_const(param->arg_info->type_hint), 1); + } +} + /* {{{ proto public bool ReflectionParameter::isArray() Returns whether parameter MUST be an array */ ZEND_METHOD(reflection_parameter, isArray) @@ -5876,14 +5895,14 @@ static const zend_function_entry reflection_property_functions[] = { }; ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_parameter_export, 0, 0, 2) - ZEND_ARG_INFO(0, function) - ZEND_ARG_INFO(0, parameter) - ZEND_ARG_INFO(0, return) + ZEND_ARG_TYPE_INFO(0, function, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, return, IS_BOOL, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_reflection_parameter___construct, 0) - ZEND_ARG_INFO(0, function) - ZEND_ARG_INFO(0, parameter) + ZEND_ARG_TYPE_INFO(0, function, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) ZEND_END_ARG_INFO() static const zend_function_entry reflection_parameter_functions[] = { @@ -5897,6 +5916,7 @@ static const zend_function_entry reflection_parameter_functions[] = { ZEND_ME(reflection_parameter, getDeclaringFunction, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getDeclaringClass, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getClass, arginfo_reflection__void, 0) + ZEND_ME(reflection_parameter, getTypeHint, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isArray, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isCallable, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, allowsNull, arginfo_reflection__void, 0) diff --git a/tests/classes/type_hinting_006.phpt b/tests/classes/type_hinting_006.phpt new file mode 100644 index 0000000000000..a4b3619af46db --- /dev/null +++ b/tests/classes/type_hinting_006.phpt @@ -0,0 +1,35 @@ +--TEST-- +Getting the right type hinting information +--FILE-- +getMethod("export"); +$p = $m->getParameters(); +foreach ($p as $i) + var_dump($i->getTypeHint()); +echo "\n"; + +// Other method with type info +$m = $c->getMethod("__construct"); +$p = $m->getParameters(); +foreach ($p as $i) + var_dump($i->getTypeHint()); +echo "\n"; + +// Function with missing type info (at least for now) +$f = new ReflectionFunction("urlencode"); +$p = $f->getParameters(); +foreach ($p as $i) + var_dump($i->getTypeHint()); +?> +--EXPECT-- +string(6) "string" +string(6) "string" +string(7) "boolean" + +string(6) "string" +string(6) "string" + +NULL