]> granicus.if.org Git - php/commitdiff
Add string or object ZPP macros
authorMáté Kocsis <kocsismate@woohoolabs.com>
Tue, 30 Jun 2020 13:04:54 +0000 (15:04 +0200)
committerMáté Kocsis <kocsismate@woohoolabs.com>
Mon, 6 Jul 2020 10:42:02 +0000 (12:42 +0200)
Closes GH-5788

Zend/tests/str_or_obj_of_class_zpp.phpt [new file with mode: 0644]
Zend/tests/str_or_obj_zpp.phpt [new file with mode: 0644]
Zend/zend_API.c
Zend/zend_API.h
ext/zend_test/test.c
ext/zend_test/test.stub.php
ext/zend_test/test_arginfo.h

diff --git a/Zend/tests/str_or_obj_of_class_zpp.phpt b/Zend/tests/str_or_obj_of_class_zpp.phpt
new file mode 100644 (file)
index 0000000..b8c38ba
--- /dev/null
@@ -0,0 +1,61 @@
+--TEST--
+Test Z_PARAM_STR_OR_OBJ_OF_CLASS() and Z_PARAM_STR_OR_OBJ_OF_CLASS_OR_NULL
+--SKIPIF--
+<?php
+if (!extension_loaded('zend-test')) die('skip zend-test extension not loaded');
+?>
+--FILE--
+<?php
+
+class Foo {}
+
+var_dump(zend_string_or_stdclass("string"));
+var_dump(zend_string_or_stdclass(1));
+var_dump(zend_string_or_stdclass(null));
+var_dump(zend_string_or_stdclass(new stdClass()));
+
+try {
+    zend_string_or_stdclass([]);
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+try {
+    zend_string_or_stdclass(new Foo());
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+var_dump(zend_string_or_stdclass_or_null("string"));
+var_dump(zend_string_or_stdclass_or_null(1));
+var_dump(zend_string_or_stdclass_or_null(null));
+var_dump(zend_string_or_stdclass_or_null(new stdClass()));
+
+try {
+    zend_string_or_stdclass_or_null([]);
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+try {
+    zend_string_or_stdclass_or_null(new Foo());
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+string(6) "string"
+string(1) "1"
+string(0) ""
+object(stdClass)#1 (0) {
+}
+zend_string_or_stdclass(): Argument #1 ($param) must be of type stdClass|string, array given
+zend_string_or_stdclass(): Argument #1 ($param) must be of type stdClass|string, Foo given
+string(6) "string"
+string(1) "1"
+NULL
+object(stdClass)#1 (0) {
+}
+zend_string_or_stdclass_or_null(): Argument #1 ($param) must be of type stdClass|string|null, array given
+zend_string_or_stdclass_or_null(): Argument #1 ($param) must be of type stdClass|string|null, Foo given
diff --git a/Zend/tests/str_or_obj_zpp.phpt b/Zend/tests/str_or_obj_zpp.phpt
new file mode 100644 (file)
index 0000000..386558e
--- /dev/null
@@ -0,0 +1,53 @@
+--TEST--
+Test Z_PARAM_STR_OR_OBJ() and Z_PARAM_STR_OR_OBJ_OR_NULL
+--SKIPIF--
+<?php
+if (!extension_loaded('zend-test')) die('skip zend-test extension not loaded');
+?>
+--FILE--
+<?php
+
+class Foo {}
+
+var_dump(zend_string_or_object("string"));
+var_dump(zend_string_or_object(1));
+var_dump(zend_string_or_object(null));
+var_dump(zend_string_or_object(new stdClass()));
+var_dump(zend_string_or_object(new Foo()));
+
+try {
+    zend_string_or_object([]);
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+var_dump(zend_string_or_object_or_null("string"));
+var_dump(zend_string_or_object_or_null(1));
+var_dump(zend_string_or_object_or_null(null));
+var_dump(zend_string_or_object_or_null(new stdClass()));
+var_dump(zend_string_or_object_or_null(new Foo()));
+
+try {
+    zend_string_or_object_or_null([]);
+} catch (TypeError $exception) {
+    echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+string(6) "string"
+string(1) "1"
+string(0) ""
+object(stdClass)#1 (0) {
+}
+object(Foo)#1 (0) {
+}
+zend_string_or_object(): Argument #1 ($param) must be of type object|string, array given
+string(6) "string"
+string(1) "1"
+NULL
+object(stdClass)#2 (0) {
+}
+object(Foo)#2 (0) {
+}
+zend_string_or_object_or_null(): Argument #1 ($param) must be of type object|string|null, array given
index 14075847ad1f5c088399feb71593c95cf0ac0fc9..4aa0103ae50621bac58e9b99fca294d177e22b3a 100644 (file)
@@ -252,6 +252,26 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(i
 }
 /* }}} */
 
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_error(int num, const char *name, zval *arg) /* {{{ */
+{
+       if (EG(exception)) {
+               return;
+       }
+
+       zend_argument_type_error(num, "must be of type %s|string, %s given", name, zend_zval_type_name(arg));
+}
+/* }}} */
+
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_or_null_error(int num, const char *name, zval *arg) /* {{{ */
+{
+       if (EG(exception)) {
+               return;
+       }
+
+       zend_argument_type_error(num, "must be of type %s|string|null, %s given", name, zend_zval_type_name(arg));
+}
+/* }}} */
+
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int num, char *error) /* {{{ */
 {
        if (EG(exception)) {
index ae0363f7657bc2b62caf5ff7cfa8a2a578109862..578cf629f836bd7cc4532aab91908263c997e9ca 100644 (file)
@@ -1219,6 +1219,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
        _(Z_EXPECTED_STRING_OR_LONG_OR_NULL, "of type string|int|null") \
        _(Z_EXPECTED_CLASS_NAME_OR_OBJECT,      "a valid class name or object") \
        _(Z_EXPECTED_CLASS_NAME_OR_OBJECT_OR_NULL, "a valid class name, object, or null") \
+       _(Z_EXPECTED_STRING_OR_OBJECT,  "of type object|string") \
+       _(Z_EXPECTED_STRING_OR_OBJECT_OR_NULL, "of type object|string|null") \
 
 #define Z_EXPECTED_TYPE
 
@@ -1235,18 +1237,22 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(int min_
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(int num, zend_expected_type expected_type, zval *arg);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(int num, const char *name, zval *arg);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(int num, const char *name, zval *arg);
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_error(int num, const char *name, zval *arg);
+ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_string_or_class_or_null_error(int num, const char *name, zval *arg);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int num, char *error);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_type_error(uint32_t arg_num, const char *format, ...);
 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num, const char *format, ...);
 
-#define ZPP_ERROR_OK                                   0
-#define ZPP_ERROR_FAILURE                              1
-#define ZPP_ERROR_WRONG_CALLBACK               2
-#define ZPP_ERROR_WRONG_CLASS                  3
-#define ZPP_ERROR_WRONG_CLASS_OR_NULL  4
-#define ZPP_ERROR_WRONG_ARG                            5
-#define ZPP_ERROR_WRONG_COUNT                  6
+#define ZPP_ERROR_OK                            0
+#define ZPP_ERROR_FAILURE                       1
+#define ZPP_ERROR_WRONG_CALLBACK                2
+#define ZPP_ERROR_WRONG_CLASS                   3
+#define ZPP_ERROR_WRONG_CLASS_OR_NULL           4
+#define ZPP_ERROR_WRONG_ARG                     5
+#define ZPP_ERROR_WRONG_COUNT                   6
+#define ZPP_ERROR_WRONG_STRING_OR_CLASS         7
+#define ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL 8
 
 #define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
                const int _flags = (flags); \
@@ -1301,6 +1307,10 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num
                                        zend_wrong_parameter_class_or_null_error(_i, _error, _arg); \
                                } else if (_error_code == ZPP_ERROR_WRONG_ARG) { \
                                        zend_wrong_parameter_type_error(_i, _expected_type, _arg); \
+                               } else if (_error_code == ZPP_ERROR_WRONG_STRING_OR_CLASS) { \
+                                       zend_wrong_parameter_string_or_class_error(_i, _error, _arg); \
+                               } else if (_error_code == ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL) { \
+                                       zend_wrong_parameter_string_or_class_or_null_error(_i, _error, _arg); \
                                } \
                        } \
                        failure; \
@@ -1411,6 +1421,40 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num
 #define Z_PARAM_CLASS_NAME_OR_OBJ_OR_NULL(dest) \
        Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, 1);
 
+#define Z_PARAM_STR_OR_OBJ_EX(destination_string, destination_object, allow_null) \
+       Z_PARAM_PROLOGUE(0, 0); \
+       if (UNEXPECTED(!zend_parse_arg_str_or_obj(_arg, &destination_string, &destination_object, NULL, allow_null))) { \
+               _expected_type = allow_null ? Z_EXPECTED_STRING_OR_OBJECT_OR_NULL : Z_EXPECTED_STRING_OR_OBJECT; \
+               _error_code = ZPP_ERROR_WRONG_ARG; \
+               break; \
+       }
+
+#define Z_PARAM_STR_OR_OBJ(destination_string, destination_object) \
+       Z_PARAM_STR_OR_OBJ_EX(destination_string, destination_object, 0);
+
+#define Z_PARAM_STR_OR_OBJ_OR_NULL(destination_string, destination_object) \
+       Z_PARAM_STR_OR_OBJ_EX(destination_string, destination_object, 1);
+
+#define Z_PARAM_STR_OR_OBJ_OF_CLASS_EX(destination_string, destination_object, base_ce, allow_null) \
+       Z_PARAM_PROLOGUE(0, 0); \
+       if (UNEXPECTED(!zend_parse_arg_str_or_obj(_arg, &destination_string, &destination_object, base_ce, allow_null))) { \
+               if (base_ce) { \
+                       _error = ZSTR_VAL((base_ce)->name); \
+                       _error_code = allow_null ? ZPP_ERROR_WRONG_STRING_OR_CLASS_OR_NULL : ZPP_ERROR_WRONG_STRING_OR_CLASS; \
+                       break; \
+               } else { \
+                       _expected_type = allow_null ? Z_EXPECTED_STRING_OR_OBJECT_OR_NULL : Z_EXPECTED_STRING_OR_OBJECT; \
+                       _error_code = ZPP_ERROR_WRONG_ARG; \
+                       break; \
+               } \
+       }
+
+#define Z_PARAM_STR_OR_OBJ_OF_CLASS(destination_string, destination_object, base_ce) \
+       Z_PARAM_STR_OR_OBJ_OF_CLASS_EX(destination_string, destination_object, base_ce, 0);
+
+#define Z_PARAM_STR_OR_OBJ_OF_CLASS_OR_NULL(destination_string, destination_object, base_ce) \
+       Z_PARAM_STR_OR_OBJ_OF_CLASS_EX(destination_string, destination_object, base_ce, 1);
+
 /* old "d" */
 #define Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, deref, separate) \
                Z_PARAM_PROLOGUE(deref, separate); \
@@ -1972,6 +2016,30 @@ static zend_always_inline int zend_parse_arg_class_name_or_obj(
        return 1;
 }
 
+static zend_always_inline int zend_parse_arg_str_or_obj(
+       zval *arg, zend_string **destination_string, zend_object **destination_object, zend_class_entry *base_ce, int allow_null
+) {
+       if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
+               if (base_ce && UNEXPECTED(!instanceof_function(Z_OBJCE_P(arg), base_ce))) {
+                       return 0;
+               }
+
+               *destination_string = NULL;
+               *destination_object = Z_OBJ_P(arg);
+       } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
+               *destination_string = Z_STR_P(arg);
+               *destination_object = NULL;
+       } else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
+               *destination_string = NULL;
+               *destination_object = NULL;
+       } else {
+               *destination_object = NULL;
+               return zend_parse_arg_str_slow(arg, destination_string);
+       }
+
+       return 1;
+}
+
 END_EXTERN_C()
 
 #endif /* ZEND_API_H */
index bc412305ed28447d61f99f938f319546034888a4..92408866d661903cde43c71496d38421928e59b4 100644 (file)
@@ -132,6 +132,82 @@ ZEND_FUNCTION(zend_leak_variable)
 }
 /* }}} */
 
+/* Tests Z_PARAM_STR_OR_OBJ */
+ZEND_FUNCTION(zend_string_or_object)
+{
+       zend_string *str;
+       zend_object *object;
+
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR_OR_OBJ(str, object)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (str) {
+               RETURN_STR_COPY(str);
+       } else {
+               RETURN_OBJ_COPY(object);
+       }
+}
+/* }}} */
+
+/* Tests Z_PARAM_STR_OR_OBJ_OR_NULL */
+ZEND_FUNCTION(zend_string_or_object_or_null)
+{
+       zend_string *str;
+       zend_object *object;
+
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR_OR_OBJ_OR_NULL(str, object)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (str) {
+               RETURN_STR_COPY(str);
+       } else if (object) {
+               RETURN_OBJ_COPY(object);
+       } else {
+               RETURN_NULL();
+       }
+}
+/* }}} */
+
+/* Tests Z_PARAM_STR_OR_OBJ_OF_CLASS */
+ZEND_FUNCTION(zend_string_or_stdclass)
+{
+       zend_string *str;
+       zend_object *object;
+
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR_OR_OBJ_OF_CLASS(str, object, zend_standard_class_def)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (str) {
+               RETURN_STR_COPY(str);
+       } else {
+               RETURN_OBJ_COPY(object);
+       }
+}
+/* }}} */
+
+/* Tests Z_PARAM_STR_OR_OBJ_OF_CLASS_OR_NULL */
+ZEND_FUNCTION(zend_string_or_stdclass_or_null)
+{
+       zend_string *str;
+       zend_object *object;
+
+       ZEND_PARSE_PARAMETERS_START(1, 1)
+               Z_PARAM_STR_OR_OBJ_OF_CLASS_OR_NULL(str, object, zend_standard_class_def)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (str) {
+               RETURN_STR_COPY(str);
+       } else if (object) {
+               RETURN_OBJ_COPY(object);
+       } else {
+               RETURN_NULL();
+       }
+}
+/* }}} */
+
 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);
index 232c268168b9257075527f76e192f974e2f66d3b..0cc00b4a326600d868a75b880499f49f1fb5874c 100644 (file)
@@ -29,3 +29,13 @@ function zend_terminate_string(string &$str): void {}
 function zend_leak_variable(mixed $variable): void {}
 
 function zend_leak_bytes(int $bytes = 3): void {}
+
+function zend_string_or_object(object|string $param): object|string {}
+
+function zend_string_or_object_or_null(object|string|null $param): object|string|null {}
+
+/** @param stdClass|string $param */
+function zend_string_or_stdclass($param): stdClass|string {}
+
+/** @param stdClass|string|null $param */
+function zend_string_or_stdclass_or_null($param): stdClass|string|null {}
index 334d9caea311b96d7d0fb9ee1c615967d7ae7a35..d65ce2220ca5de906524af294e853375fbf6d1b1 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: a61df45ef2431d449b0ac546640101db8ce66445 */
+ * Stub hash: d04baf2ffeb73d2e48f806316407ec720ea6f176 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
 ZEND_END_ARG_INFO()
@@ -28,6 +28,22 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_leak_bytes, 0, 0, IS_VOID,
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bytes, IS_LONG, 0, "3")
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_zend_string_or_object, 0, 1, MAY_BE_OBJECT|MAY_BE_STRING)
+       ZEND_ARG_TYPE_MASK(0, param, MAY_BE_OBJECT|MAY_BE_STRING, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_zend_string_or_object_or_null, 0, 1, MAY_BE_OBJECT|MAY_BE_STRING|MAY_BE_NULL)
+       ZEND_ARG_TYPE_MASK(0, param, MAY_BE_OBJECT|MAY_BE_STRING|MAY_BE_NULL, NULL)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_zend_string_or_stdclass, 0, 1, stdClass, MAY_BE_STRING)
+       ZEND_ARG_INFO(0, param)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_zend_string_or_stdclass_or_null, 0, 1, stdClass, MAY_BE_STRING|MAY_BE_NULL)
+       ZEND_ARG_INFO(0, param)
+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()
 
@@ -46,6 +62,10 @@ ZEND_FUNCTION(zend_create_unterminated_string);
 ZEND_FUNCTION(zend_terminate_string);
 ZEND_FUNCTION(zend_leak_variable);
 ZEND_FUNCTION(zend_leak_bytes);
+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_METHOD(_ZendTestClass, is_object);
 ZEND_METHOD(_ZendTestClass, __toString);
 ZEND_METHOD(_ZendTestTrait, testMethod);
@@ -60,6 +80,10 @@ static const zend_function_entry ext_functions[] = {
        ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string)
        ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable)
        ZEND_FE(zend_leak_bytes, arginfo_zend_leak_bytes)
+       ZEND_FE(zend_string_or_object, arginfo_zend_string_or_object)
+       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_END
 };