diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 89333d89af9df..1cbeed619ae5f 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2997,6 +2997,7 @@ ZEND_API void zend_convert_internal_arg_info(zend_arg_info *new_arg_info, const new_arg_info->name = NULL; new_arg_info->default_value = NULL; } + new_arg_info->doc_comment = NULL; new_arg_info->type = arg_info->type; zend_convert_internal_arg_info_type(&new_arg_info->type, persistent); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 23db72bb4fda1..d35c8b6d57eae 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8024,6 +8024,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 } else { arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0); } + arg_infos->doc_comment = NULL; arg_infos++; op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE; @@ -8122,6 +8123,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 arg_info->name = zend_string_copy(name); arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0); arg_info->default_value = NULL; + arg_info->doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; if (attributes_ast) { zend_compile_attributes( diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0b38084a107cd..5dec6394490d9 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -515,6 +515,7 @@ typedef struct _zend_arg_info { zend_string *name; zend_type type; zend_string *default_value; + zend_string *doc_comment; } zend_arg_info; /* the following structure repeats the layout of zend_internal_arg_info, diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e2686c7e1c5a8..dbd61319de611 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -817,13 +817,13 @@ optional_cpp_modifiers: parameter: optional_cpp_modifiers optional_type_without_static - is_reference is_variadic T_VARIABLE backup_doc_comment optional_property_hook_list + is_reference is_variadic T_VARIABLE optional_property_hook_list backup_doc_comment { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, NULL, - NULL, $6 ? zend_ast_create_zval_from_str($6) : NULL, $7); } + NULL, $7 ? zend_ast_create_zval_from_str($7) : NULL, $6); } | optional_cpp_modifiers optional_type_without_static - is_reference is_variadic T_VARIABLE backup_doc_comment '=' expr optional_property_hook_list - { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, $8, - NULL, $6 ? zend_ast_create_zval_from_str($6) : NULL, $9); } + is_reference is_variadic T_VARIABLE '=' expr optional_property_hook_list backup_doc_comment + { $$ = zend_ast_create_ex(ZEND_AST_PARAM, $1 | $3 | $4, $2, $5, $7, + NULL, $9 ? zend_ast_create_zval_from_str($9) : NULL, $8); } ; optional_type_without_static: diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 24b480ad71e66..35de02b557298 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -648,6 +648,9 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (arg_info[i].name) { zend_string_release_ex(arg_info[i].name, 0); } + if (arg_info[i].doc_comment) { + zend_string_release_ex(arg_info[i].doc_comment, 0); + } zend_type_release(arg_info[i].type, /* persistent */ false); } efree(arg_info); diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 9bc2496837ce4..568db085bb2c4 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -652,6 +652,9 @@ static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_sc zend_accel_store_interned_string(arg_info[i].name); } zend_persist_type(&arg_info[i].type); + if (arg_info[i].doc_comment) { + zend_accel_store_interned_string(arg_info[i].doc_comment); + } } if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { arg_info++; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 0b0ff51d0d4df..657cc03eb3901 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -306,6 +306,9 @@ static void zend_persist_op_array_calc_ex(zend_op_array *op_array) ADD_INTERNED_STRING(arg_info[i].name); } zend_persist_type_calc(&arg_info[i].type); + if (arg_info[i].doc_comment) { + ADD_INTERNED_STRING(arg_info[i].doc_comment); + } } } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 232c1e6b36a85..1867180da9564 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2653,6 +2653,21 @@ ZEND_METHOD(ReflectionParameter, __toString) /* }}} */ +/* {{{ Returns the doc comment for this function */ +ZEND_METHOD(ReflectionParameter, getDocComment) +{ + reflection_object *intern; + parameter_reference *param; + + ZEND_PARSE_PARAMETERS_NONE(); + + GET_REFLECTION_OBJECT_PTR(param); + if (param->arg_info->doc_comment) { + RETURN_STR_COPY(param->arg_info->doc_comment); + } + RETURN_FALSE; +} + /* {{{ Returns this parameter's name */ ZEND_METHOD(ReflectionParameter, getName) { diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 8f2c49460b4a5..f3c46e43e5131 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -648,6 +648,9 @@ public function __construct($function, int|string $param) {} public function __toString(): string {} + /** @tentative-return-type */ + public function getDocComment(): string|false {} + /** @tentative-return-type */ public function getName(): string {} diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index e16ea82b0e957..ee94099925c5e 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: b09497083efa7035dab6047f6d845ceaec81579e + * Stub hash: 75f975e31f78446c918d29ca14321e7b1ad0b0c6 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) @@ -519,6 +519,8 @@ ZEND_END_ARG_INFO() #define arginfo_class_ReflectionParameter___toString arginfo_class_ReflectionFunction___toString +#define arginfo_class_ReflectionParameter_getDocComment arginfo_class_ReflectionFunctionAbstract_getDocComment + #define arginfo_class_ReflectionParameter_getName arginfo_class_ReflectionFunctionAbstract_getName #define arginfo_class_ReflectionParameter_isPassedByReference arginfo_class_ReflectionFunctionAbstract_inNamespace @@ -912,6 +914,7 @@ ZEND_METHOD(ReflectionClassConstant, hasType); ZEND_METHOD(ReflectionClassConstant, getType); ZEND_METHOD(ReflectionParameter, __construct); ZEND_METHOD(ReflectionParameter, __toString); +ZEND_METHOD(ReflectionParameter, getDocComment); ZEND_METHOD(ReflectionParameter, getName); ZEND_METHOD(ReflectionParameter, isPassedByReference); ZEND_METHOD(ReflectionParameter, canBePassedByValue); @@ -1226,6 +1229,7 @@ static const zend_function_entry class_ReflectionParameter_methods[] = { ZEND_RAW_FENTRY("__clone", zim_ReflectionClass___clone, arginfo_class_ReflectionParameter___clone, ZEND_ACC_PRIVATE, NULL, NULL) ZEND_ME(ReflectionParameter, __construct, arginfo_class_ReflectionParameter___construct, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, __toString, arginfo_class_ReflectionParameter___toString, ZEND_ACC_PUBLIC) + ZEND_ME(ReflectionParameter, getDocComment, arginfo_class_ReflectionParameter_getDocComment, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, getName, arginfo_class_ReflectionParameter_getName, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, isPassedByReference, arginfo_class_ReflectionParameter_isPassedByReference, ZEND_ACC_PUBLIC) ZEND_ME(ReflectionParameter, canBePassedByValue, arginfo_class_ReflectionParameter_canBePassedByValue, ZEND_ACC_PUBLIC) diff --git a/ext/reflection/php_reflection_decl.h b/ext/reflection/php_reflection_decl.h index f93c1d0c887de..14d80b786ad85 100644 --- a/ext/reflection/php_reflection_decl.h +++ b/ext/reflection/php_reflection_decl.h @@ -1,12 +1,12 @@ /* This is a generated file, edit php_reflection.stub.php instead. - * Stub hash: b09497083efa7035dab6047f6d845ceaec81579e */ + * Stub hash: 75f975e31f78446c918d29ca14321e7b1ad0b0c6 */ -#ifndef ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H -#define ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H +#ifndef ZEND_PHP_REFLECTION_DECL_75f975e31f78446c918d29ca14321e7b1ad0b0c6_H +#define ZEND_PHP_REFLECTION_DECL_75f975e31f78446c918d29ca14321e7b1ad0b0c6_H typedef enum zend_enum_PropertyHookType { ZEND_ENUM_PropertyHookType_Get = 1, ZEND_ENUM_PropertyHookType_Set = 2, } zend_enum_PropertyHookType; -#endif /* ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H */ +#endif /* ZEND_PHP_REFLECTION_DECL_75f975e31f78446c918d29ca14321e7b1ad0b0c6_H */ diff --git a/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt b/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt new file mode 100644 index 0000000000000..87d201a74e389 --- /dev/null +++ b/ext/reflection/tests/ReflectionParameter_getDocComment_basic.phpt @@ -0,0 +1,72 @@ +--TEST-- +Test ReflectionParameter::getDocComment() usage. +--INI-- +opcache.save_comments=1 +--FILE-- +getParameters(); + foreach($rps as $rp) { + echo "\n\n---> Doc comment for $function $" . $rp->getName() . ":\n"; + var_dump($rp->getDocComment()); + } +} + +?> +--EXPECTF-- +---> Doc comment for func $a: +string(%d) "/** + * My Doc Comment for $a + * + */" + + +---> Doc comment for func $b: +bool(false) + + +---> Doc comment for func $c: +bool(false) + + +---> Doc comment for func $d: +string(%d) "/** + * My Doc Comment for $d + */" + + +---> Doc comment for func $e: +bool(false) + + +---> Doc comment for func $f: +string(%d) "/** + * Doc comment for $f + */" + + +---> Doc comment for func $g: +string(%d) "/** Doc comment for $g behind parameter */" + +