diff --git a/Zend/tests/010.phpt b/Zend/tests/010.phpt index a4a862cac220..351398ecfa85 100644 --- a/Zend/tests/010.phpt +++ b/Zend/tests/010.phpt @@ -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"; ?> @@ -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 diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 9744612ac746..39c4be3e0d02 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -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 @@ -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); \ @@ -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); \ @@ -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); \ @@ -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 */ @@ -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; + return 0; + } + + return 1; +} + END_EXTERN_C() #endif /* ZEND_API_H */ diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 521c2c32de19..881624d321a8 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -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) { diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 9e5078f14a9c..a79aced5fed7 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -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 {} diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index df1f06888ee9..c464a540a1ff 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -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) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0b4520566fe0..6813b60e624c 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); @@ -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); diff --git a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt index 8d3e64e92515..a8c8e1711760 100644 --- a/ext/standard/tests/class_object/get_parent_class_variation_002.phpt +++ b/ext/standard/tests/class_object/get_parent_class_variation_002.phpt @@ -70,10 +70,14 @@ $values = array( // loop through each element of the array for object -foreach($values as $value) { - echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . " \n"; - var_dump( get_parent_class($value) ); -}; +foreach ($values as $value) { + echo "\nArg value " . (is_object($value) ? get_class($value) : $value) . "\n"; + try { + var_dump(get_parent_class($value)); + } catch (TypeError $exception) { + echo $exception->getMessage() . "\n"; + } +} echo "Done"; ?> @@ -82,91 +86,91 @@ echo "Done"; Error: 2 - Undefined variable $undefined_var Error: 2 - Undefined variable $unset_var -Arg value 0 -bool(false) +Arg value 0 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given -Arg value 1 -bool(false) +Arg value 1 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given -Arg value 12345 -bool(false) +Arg value 12345 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given -Arg value -2345 -bool(false) +Arg value -2345 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, int given -Arg value 10.5 -bool(false) +Arg value 10.5 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given -Arg value -10.5 -bool(false) +Arg value -10.5 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given -Arg value 101234567000 -bool(false) +Arg value 101234567000 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given -Arg value 1.07654321E-9 -bool(false) +Arg value 1.07654321E-9 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given -Arg value 0.5 -bool(false) +Arg value 0.5 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, float given Error: 2 - Array to string conversion -Arg value Array -bool(false) +Arg value Array +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion -Arg value Array -bool(false) +Arg value Array +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion -Arg value Array -bool(false) +Arg value Array +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion -Arg value Array -bool(false) +Arg value Array +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given Error: 2 - Array to string conversion -Arg value Array -bool(false) +Arg value Array +get_parent_class(): Argument #1 ($object) must be a valid class name or object, array given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given -Arg value 1 -bool(false) +Arg value 1 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given -Arg value 1 -bool(false) +Arg value 1 +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, bool given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given -Arg value string +Arg value string In autoload(string) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given -Arg value String +Arg value String In autoload(String) -bool(false) +get_parent_class(): Argument #1 ($object) must be a valid class name or object, string given -Arg value stdClass +Arg value stdClass bool(false) -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given -Arg value -bool(false) +Arg value +get_parent_class(): Argument #1 ($object) must be a valid class name or object, null given Done