diff --git a/NEWS b/NEWS index 754ab95409e60..6af8ce6b2cb9c 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ PHP NEWS . Fix OSS-Fuzz #472563272 (Borked block_pass JMP[N]Z optimization). (ilutov) . Fixed bug GH-20914 (Internal enums can be cloned and compared). (Arnaud) . Fix OSS-Fuzz #474613951 (Leaked parent property default value). (ilutov) + . Fixed bug GH-20895 (ReflectionProperty does not return the PHPDoc of a + property if it contains an attribute with a Closure). (timwolla) - MbString: . Fixed bug GH-20833 (mb_str_pad() divide by zero if padding string is diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index e4d61006fe12f..897abbbe97734 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -379,7 +379,7 @@ attribute_group: ; attribute: - T_ATTRIBUTE attribute_group possible_comma ']' { $$ = $2; } + T_ATTRIBUTE backup_doc_comment attribute_group possible_comma ']' { $$ = $3; CG(doc_comment) = $2; } ; attributes: diff --git a/ext/reflection/tests/gh20895.phpt b/ext/reflection/tests/gh20895.phpt new file mode 100644 index 0000000000000..f281078de4463 --- /dev/null +++ b/ext/reflection/tests/gh20895.phpt @@ -0,0 +1,108 @@ +--TEST-- +GH-20895: ReflectionProperty does not return the PHPDoc of a property if it contains an attribute with a Closure +--FILE-- +getDocComment()); +foreach ((new ReflectionClass(Foo::class))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionProperty(Foo::class, 'bar'))->getDocComment()); +foreach ((new ReflectionProperty(Foo::class, 'bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionMethod(Foo::class, 'bar'))->getDocComment()); +foreach ((new ReflectionMethod(Foo::class, 'bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('foo'))->getDocComment()); +foreach ((new ReflectionFunction('foo'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('bar'))->getDocComment()); +foreach ((new ReflectionFunction('bar'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} +var_dump((new ReflectionFunction('baz'))->getDocComment()); +foreach ((new ReflectionFunction('baz'))->getAttributes() as $attribute) { + foreach ($attribute->getArguments() as $argument) { + var_dump((new ReflectionFunction($argument))->getDocComment()); + } +} + +?> +--EXPECT-- +string(10) "/** Foo */" +string(16) "/** Closure 1 */" +string(16) "/** Closure 2 */" +string(16) "/** Foo::$bar */" +string(16) "/** Closure 3 */" +string(16) "/** Closure 4 */" +string(16) "/** Closure 5 */" +string(17) "/** Foo::bar() */" +string(16) "/** Closure 6 */" +string(12) "/** foo() */" +string(16) "/** Closure 7 */" +string(12) "/** bar() */" +string(16) "/** Closure 8 */" +string(12) "/** baz() */" +bool(false)