From: Levi Morrison Date: Thu, 3 Sep 2020 13:03:12 +0000 (-0600) Subject: Add Z_PARAM_ITERABLE and co X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=94fd52dd091051d4d4089c4c89b68fee6a876e23;p=php Add Z_PARAM_ITERABLE and co --- diff --git a/Zend/tests/iterable_or_null.phpt b/Zend/tests/iterable_or_null.phpt new file mode 100644 index 0000000000..9f798af06d --- /dev/null +++ b/Zend/tests/iterable_or_null.phpt @@ -0,0 +1,49 @@ +--TEST-- +Test Z_PARAM_ITERABLE() and Z_PARAM_ITERABLE_OR_NULL +--SKIPIF-- + +--FILE-- +getMessage() . "\n"; +} + +try { + var_dump(zend_iterable(1)); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +try { + var_dump(zend_iterable(null)); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + + +zend_iterable([]); +zend_iterable([], []); + +$iterator = new ArrayIterator([]); +zend_iterable($iterator); +zend_iterable($iterator, $iterator); +zend_iterable($iterator, null); + +try { + var_dump(zend_iterable([], "string")); +} catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; +} + +?> +--EXPECT-- +zend_iterable(): Argument #1 ($arg1) must be of type iterable, string given +zend_iterable(): Argument #1 ($arg1) must be of type iterable, int given +zend_iterable(): Argument #1 ($arg1) must be of type iterable, null given +zend_iterable(): Argument #2 ($arg2) must be of type ?iterable, string given + diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 70e757c1bb..a81a43f231 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -1209,6 +1209,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv) _(Z_EXPECTED_STRING_OR_NULL, "of type ?string") \ _(Z_EXPECTED_ARRAY, "of type array") \ _(Z_EXPECTED_ARRAY_OR_NULL, "of type ?array") \ + _(Z_EXPECTED_ITERABLE, "of type iterable") \ + _(Z_EXPECTED_ITERABLE_OR_NULL, "of type ?iterable") \ _(Z_EXPECTED_FUNC, "a valid callback") \ _(Z_EXPECTED_FUNC_OR_NULL, "a valid callback or null") \ _(Z_EXPECTED_RESOURCE, "of type resource") \ @@ -1373,6 +1375,20 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char * #define Z_PARAM_ARRAY_OR_OBJECT(dest) \ Z_PARAM_ARRAY_OR_OBJECT_EX(dest, 0, 0) +#define Z_PARAM_ITERABLE_EX(dest, check_null) \ + Z_PARAM_PROLOGUE(0, 0); \ + if (UNEXPECTED(!zend_parse_arg_iterable(_arg, &dest, check_null))) { \ + _expected_type = check_null ? Z_EXPECTED_ITERABLE_OR_NULL : Z_EXPECTED_ITERABLE; \ + _error_code = ZPP_ERROR_WRONG_ARG; \ + break; \ + } + +#define Z_PARAM_ITERABLE(dest) \ + Z_PARAM_ITERABLE_EX(dest, 0) + +#define Z_PARAM_ITERABLE_OR_NULL(dest) \ + Z_PARAM_ITERABLE_EX(dest, 1) + /* old "b" */ #define Z_PARAM_BOOL_EX2(dest, is_null, check_null, deref, separate) \ Z_PARAM_PROLOGUE(deref, separate); \ @@ -1903,6 +1919,21 @@ static zend_always_inline bool zend_parse_arg_path(zval *arg, char **dest, size_ return 1; } +static zend_always_inline bool zend_parse_arg_iterable(zval *arg, zval **dest, bool check_null) +{ + if (EXPECTED(zend_is_iterable(arg))) { + *dest = arg; + return 1; + } + + if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) { + *dest = NULL; + return 1; + } + + return 0; +} + static zend_always_inline bool zend_parse_arg_array(zval *arg, zval **dest, bool check_null, bool or_object) { if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY) || diff --git a/build/gen_stub.php b/build/gen_stub.php index 214d1f563e..de2d3b144b 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -112,6 +112,8 @@ class SimpleType { return "IS_VOID"; case "callable": return "IS_CALLABLE"; + case "iterable": + return "IS_ITERABLE"; case "mixed": return "IS_MIXED"; default: diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 2d91543cf1..18e7443313 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -221,6 +221,18 @@ ZEND_FUNCTION(zend_string_or_stdclass_or_null) } /* }}} */ +/* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */ +ZEND_FUNCTION(zend_iterable) +{ + zval *arg1, *arg2; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ITERABLE(arg1) + Z_PARAM_OPTIONAL + Z_PARAM_ITERABLE_OR_NULL(arg2) + ZEND_PARSE_PARAMETERS_END(); +} + static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */ { zend_object *obj = zend_objects_new(class_type); object_properties_init(obj, class_type); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index cc4a561f54..1dd0cfec4e 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -39,3 +39,5 @@ function zend_string_or_stdclass($param): stdClass|string {} /** @param stdClass|string|null $param */ function zend_string_or_stdclass_or_null($param): stdClass|string|null {} + +function zend_iterable(iterable $arg1, ?iterable $arg2 = null): void {} diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index ae7cd77b58..bd8d477b42 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 82fd97d4985448884141842955a4bee2c90ba338 */ + * Stub hash: 87c9d71b08c538c28b4f9bad01d7a7a3a3b191ef */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -46,6 +46,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_zend_string_or_stdclass_or_n ZEND_ARG_INFO(0, param) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_iterable, 0, 1, IS_VOID, 0) + ZEND_ARG_TYPE_INFO(0, arg1, IS_ITERABLE, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_ITERABLE, 1, "null") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_is_object, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -68,6 +73,7 @@ ZEND_FUNCTION(zend_string_or_object); ZEND_FUNCTION(zend_string_or_object_or_null); ZEND_FUNCTION(zend_string_or_stdclass); ZEND_FUNCTION(zend_string_or_stdclass_or_null); +ZEND_FUNCTION(zend_iterable); ZEND_METHOD(_ZendTestClass, is_object); ZEND_METHOD(_ZendTestClass, __toString); ZEND_METHOD(_ZendTestTrait, testMethod); @@ -86,6 +92,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_string_or_object_or_null, arginfo_zend_string_or_object_or_null) ZEND_FE(zend_string_or_stdclass, arginfo_zend_string_or_stdclass) ZEND_FE(zend_string_or_stdclass_or_null, arginfo_zend_string_or_stdclass_or_null) + ZEND_FE(zend_iterable, arginfo_zend_iterable) ZEND_FE_END };