mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Add string or object ZPP macros
Closes GH-5788
This commit is contained in:
parent
a4b253c40b
commit
b18b2c8fe5
7 changed files with 320 additions and 8 deletions
61
Zend/tests/str_or_obj_of_class_zpp.phpt
Normal file
61
Zend/tests/str_or_obj_of_class_zpp.phpt
Normal file
|
@ -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
|
53
Zend/tests/str_or_obj_zpp.phpt
Normal file
53
Zend/tests/str_or_obj_zpp.phpt
Normal file
|
@ -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
|
|
@ -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)) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue