Skip to content

Add ZPP macros for class name or object parameters #5647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions Zend/tests/010.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,37 @@ var_dump(get_parent_class("bar"));
var_dump(get_parent_class("foo"));
var_dump(get_parent_class("i"));

var_dump(get_parent_class(""));
var_dump(get_parent_class("[[[["));
var_dump(get_parent_class(" "));
try {
get_parent_class("");
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

try {
get_parent_class("[[[[");
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

try {
get_parent_class(" ");
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

var_dump(get_parent_class(new stdclass));
var_dump(get_parent_class(array()));
var_dump(get_parent_class(1));

try {
get_parent_class(array());
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

try {
get_parent_class(1);
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}

echo "Done\n";
?>
Expand All @@ -50,10 +75,10 @@ bool(false)
string(3) "foo"
bool(false)
bool(false)
get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given
get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given
get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given
get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given
Done
42 changes: 42 additions & 0 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
_(Z_EXPECTED_STRING_OR_ARRAY_OR_NULL, "of type string|array|null") \
_(Z_EXPECTED_STRING_OR_LONG, "of type string|int") \
_(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") \

#define Z_EXPECTED_TYPE

Expand Down Expand Up @@ -1395,6 +1397,20 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num
#define Z_PARAM_CLASS(dest) \
Z_PARAM_CLASS_EX(dest, 0, 0)

#define Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, allow_null) \
Z_PARAM_PROLOGUE(0, 0); \
if (UNEXPECTED(!zend_parse_arg_class_name_or_obj(_arg, &dest, _i, allow_null))) { \
_expected_type = allow_null ? Z_EXPECTED_CLASS_NAME_OR_OBJECT_OR_NULL : Z_EXPECTED_CLASS_NAME_OR_OBJECT; \
_error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}

#define Z_PARAM_CLASS_NAME_OR_OBJ(dest) \
Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, 0);

#define Z_PARAM_CLASS_NAME_OR_OBJ_OR_NULL(dest) \
Z_PARAM_CLASS_NAME_OR_OBJ_EX(dest, 1);

/* old "d" */
#define Z_PARAM_DOUBLE_EX2(dest, is_null, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
Expand Down Expand Up @@ -1513,6 +1529,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num
#define Z_PARAM_OBJECT(dest) \
Z_PARAM_OBJECT_EX(dest, 0, 0)

#define Z_PARAM_OBJECT_OR_NULL(dest) \
Z_PARAM_OBJECT_EX(dest, 1, 0)

/* old "O" */
#define Z_PARAM_OBJECT_OF_CLASS_EX2(dest, _ce, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
Expand All @@ -1534,6 +1553,9 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num
#define Z_PARAM_OBJECT_OF_CLASS(dest, _ce) \
Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 0, 0)

#define Z_PARAM_OBJECT_OF_CLASS_OR_NULL(dest, _ce) \
Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 1, 0)

/* old "p" */
#define Z_PARAM_PATH_EX2(dest, dest_len, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
Expand Down Expand Up @@ -1673,6 +1695,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_value_error(uint32_t arg_num

#define Z_PARAM_STR_OR_LONG_OR_NULL(dest_str, dest_long, is_null) \
Z_PARAM_STR_OR_LONG_EX(dest_str, dest_long, is_null, 1);

/* End of new parameter parsing API */

/* Inlined implementations shared by new and old parameter parsing APIs */
Expand Down Expand Up @@ -1931,6 +1954,25 @@ static zend_always_inline int zend_parse_arg_str_or_long(zval *arg, zend_string
return 1;
}

static zend_always_inline int zend_parse_arg_class_name_or_obj(
zval *arg, zend_class_entry **destination, int num, int allow_null
) {
if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
*destination = zend_lookup_class(Z_STR_P(arg));

return *destination != NULL;
} else if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
*destination = Z_OBJ_P(arg)->ce;
} else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
*destination = NULL;
} else {
*destination = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line can be dropped, we don't initialize in the failure case.

return 0;
}

return 1;
}

END_EXTERN_C()

#endif /* ZEND_API_H */
21 changes: 5 additions & 16 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,26 +637,15 @@ ZEND_FUNCTION(get_called_class)
Retrieves the parent class name for object or class or current scope or false if not in a scope. */
ZEND_FUNCTION(get_parent_class)
{
zval *arg;
zend_class_entry *ce = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg) == FAILURE) {
RETURN_THROWS();
}
ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_CLASS_NAME_OR_OBJ(ce)
ZEND_PARSE_PARAMETERS_END();

if (!ZEND_NUM_ARGS()) {
if (!ce) {
ce = zend_get_executed_scope();
if (ce && ce->parent) {
RETURN_STR_COPY(ce->parent->name);
} else {
RETURN_FALSE;
}
}

if (Z_TYPE_P(arg) == IS_OBJECT) {
ce = Z_OBJ_P(arg)->ce;
} else if (Z_TYPE_P(arg) == IS_STRING) {
ce = zend_lookup_class(Z_STR_P(arg));
}

if (ce && ce->parent) {
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_builtin_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function get_class(object $object = UNKNOWN): string {}

function get_called_class(): string {}

function get_parent_class($object = UNKNOWN): string|false {}
function get_parent_class(string|object $object = UNKNOWN): string|false {}

function is_subclass_of($object, string $class_name, bool $allow_string = true): bool {}

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_builtin_functions_arginfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ ZEND_END_ARG_INFO()
#define arginfo_get_called_class arginfo_zend_version

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_get_parent_class, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_INFO(0, object)
ZEND_ARG_TYPE_MASK(0, object, MAY_BE_STRING|MAY_BE_OBJECT, NULL)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_is_subclass_of, 0, 2, _IS_BOOL, 0)
Expand Down
12 changes: 6 additions & 6 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -2295,7 +2295,7 @@ PHP_FUNCTION(date_create)
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

php_date_instantiate(date_ce_date, return_value);
Expand All @@ -2318,7 +2318,7 @@ PHP_FUNCTION(date_create_immutable)
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

php_date_instantiate(date_ce_immutable, return_value);
Expand All @@ -2342,7 +2342,7 @@ PHP_FUNCTION(date_create_from_format)
Z_PARAM_STRING(format_str, format_str_len)
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OPTIONAL
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

php_date_instantiate(date_ce_date, return_value);
Expand All @@ -2366,7 +2366,7 @@ PHP_FUNCTION(date_create_immutable_from_format)
Z_PARAM_STRING(format_str, format_str_len)
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OPTIONAL
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

php_date_instantiate(date_ce_immutable, return_value);
Expand All @@ -2390,7 +2390,7 @@ PHP_METHOD(DateTime, __construct)
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

zend_replace_error_handling(EH_THROW, NULL, &error_handling);
Expand All @@ -2412,7 +2412,7 @@ PHP_METHOD(DateTimeImmutable, __construct)
ZEND_PARSE_PARAMETERS_START(0, 2)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(time_str, time_str_len)
Z_PARAM_OBJECT_OF_CLASS_EX(timezone_object, date_ce_timezone, 1, 0)
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
ZEND_PARSE_PARAMETERS_END();

zend_replace_error_handling(EH_THROW, NULL, &error_handling);
Expand Down
Loading