summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/str_or_obj_of_class_zpp.phpt61
-rw-r--r--Zend/tests/str_or_obj_zpp.phpt53
-rw-r--r--Zend/zend_API.c20
-rw-r--r--Zend/zend_API.h82
-rw-r--r--ext/zend_test/test.c76
-rw-r--r--ext/zend_test/test.stub.php10
-rw-r--r--ext/zend_test/test_arginfo.h26
7 files changed, 320 insertions, 8 deletions
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
index 0000000000..b8c38ba060
--- /dev/null
+++ b/Zend/tests/str_or_obj_of_class_zpp.phpt
@@ -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
index 0000000000..386558e02a
--- /dev/null
+++ b/Zend/tests/str_or_obj_zpp.phpt
@@ -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
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 14075847ad..4aa0103ae5 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -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)) {
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index ae0363f765..578cf629f8 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -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 */
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index bc412305ed..92408866d6 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -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);
diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php
index 232c268168..0cc00b4a32 100644
--- a/ext/zend_test/test.stub.php
+++ b/ext/zend_test/test.stub.php
@@ -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 {}
diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h
index 334d9caea3..d65ce2220c 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: 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
};