Skip to content

[PHP 8.6] ReflectionParameter::getDocComment() support - #227

Merged
lisachenko merged 3 commits into
masterfrom
claude/php86-221-param-doc-comments
Aug 25, 2026
Merged

[PHP 8.6] ReflectionParameter::getDocComment() support#227
lisachenko merged 3 commits into
masterfrom
claude/php86-221-param-doc-comments

Conversation

@lisachenko

@lisachenko lisachenko commented Aug 25, 2026

Copy link
Copy Markdown
Member

Refs #221 (part of epic #219).

What

PHP 8.6 allows doc comments on function/method parameters and exposes them through the new native ReflectionParameter::getDocComment(): string|false. This PR implements the same method statically from the AST, so it is available on every supported PHP version, not only on 8.6.

Changes

  • src/ReflectionParameter.php — new getDocComment(): string|false (signature-compatible with the PHP 8.6 parent; on 8.5 it is simply an extra method, the 8.5 parent has none).
  • tests/Stub/FileWithParameters86.php — new stub with the doc-comment matrix. It contains only ordinary comments, so it parses and loads on every supported PHP version and is included by the test to allow native comparison.
  • tests/ReflectionParameterTest.php — dedicated testGetDocComment() parity test, two tests pinning the known trailing-comment gap, plus getDocComment added to the generic getter parity matrix when running on PHP >= 8.6.
  • docs/reflection_parameter.md — documents the method and the known limitation.

Resolution strategy

PHP-Parser attaches a doc comment to the Param node itself only when the comment directly precedes the parameter declaration. When the comment sits inside the declaration it ends up on a nested node instead — verified with the bundled nikic/php-parser v5.8.0:

source node that receives the comment
/** doc */ string $a Param
/** doc */ #[Attr] string $a Param
#[Attr] /** doc */ string $a Identifier (the type)
#[A] /** doc */ #[B] string $a the second AttributeGroup
int $a = /** doc */ 5 the default value expression

Therefore the implementation scans the whole parameter sub-tree and picks the last doc comment in source order, which is exactly how PHP itself resolves a parameter's doc comment (its lexer remembers the most recent doc-comment token). Non-doc comments (/* … */, // …) never reset it, and the last of several doc comments wins — both verified against the 8.6 binary.

Verified parity against PHP 8.6.0beta1

Every parameter in the new stub returns byte-for-byte the same value as native reflection: leading doc comments, variadic, by-reference, nullable, union-typed, defaults (scalar/array), promoted constructor properties (public/protected), static methods, doc comment before and after attributes, several consecutive doc comments, doc comment followed by a block comment, plus the negative cases (no comment, block comment, line comment). Function/method doc comments correctly do not leak into the first parameter.

Also checked: native var_dump()/(array) cast of ReflectionParameter on 8.6 still exposes only name, so __debugInfo() / InternalPropertiesEmulationTrait needed no change. testCoverAllMethods for ReflectionParameter now passes on 8.6 (it would otherwise report getDocComment as missing).

Known parity gap

A doc comment written after the parameter it documents is reported by native reflection as belonging to that parameter, because PHP records the last doc-comment token seen while reducing the parameter rule. PHP-Parser attaches every comment to the node that follows it, and a comment sitting between the end of a parameter and the separating comma is discarded entirely, so such a trailing comment never reaches the AST at all:

function lastParameter(string $a /** doc */) {}
// native: $a => '/** doc */'                 engine: $a => false

function nextParameter(string $a /** doc */, string $b) {}
// native: $a => '/** doc */', $b => false    engine: $a => false, $b => false

Note that the comment is not mis-attributed to the following parameter — it is simply lost. This position is pathological and cannot be recovered without access to the token stream (the comma position is not available on the AST). It is documented in docs/reflection_parameter.md, in the stub, and pinned from both sides by testTrailingDocCommentIsAKnownParityGap() and testTrailingDocCommentIsLostWhenAnotherParameterFollows(), which also assert the divergent native behaviour on 8.6 so a future change in php-src or PHP-Parser is noticed.

Local results

check result
vendor/bin/phpunit (PHP 8.5.9) OK — 13764 tests, 15417 assertions, 133 skipped, 2 incomplete (pre-existing, ReflectionPropertyTest::testCoverAllMethods)
php8.6 vendor/bin/phpunit (PHP 8.6.0beta1) OK — 13892 tests, 15567 assertions, 133 skipped, 2 incomplete (same pre-existing one)
vendor/bin/phpstan analyse src --no-progress (level 10) [OK] No errors — no phpstan.neon changes needed

Baseline on master was 13743 tests on 8.5; the new tests add 21 cases on 8.5 and 149 on 8.6 (the extra ones come from getDocComment joining the generic getter parity matrix).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Sy8BcM8ivUEpu8uVm7wADn

claude added 2 commits August 25, 2026 09:53
PHP 8.6 allows doc comments on function and method parameters and exposes
them through the native `ReflectionParameter::getDocComment(): string|false`.

Implement the method statically from the AST so it is available on every
supported PHP version. PHP-Parser attaches a doc comment to the `Param` node
only when the comment directly precedes the parameter; comments placed after
an attribute group, after the type or inside a default value expression land
on nested nodes. The whole parameter sub-tree is therefore scanned and the
last doc comment in source order wins, which mirrors how PHP resolves the
doc comment of a parameter.

Add `tests/Stub/FileWithParameters86.php` covering plain, variadic,
by-reference, nullable, union-typed, promoted and attributed parameters as
well as non-doc comments, and parity tests that compare the statically
derived values with native reflection on PHP >= 8.6.

Known parity gap: a doc comment written after the parameter it documents is
still reported by native reflection but is attached by PHP-Parser to the
following node, so the engine returns false. This is documented and covered
by a dedicated test.

Refs #221

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sy8BcM8ivUEpu8uVm7wADn
…rameter

Cover the second shape of the known trailing doc comment parity gap, where
another parameter follows the comment.

Verified against PHP 8.6.0beta1 and nikic/php-parser 5.8.0: native reflection
reports the comment for the parameter it follows, while PHP-Parser discards a
comment placed between the end of a parameter and the separating comma
altogether. The comment is therefore lost rather than mis-attributed to the
next parameter, and the engine returns false for both parameters.

Add `twoParametersWithTrailingDocComment86()` to the stub, pin both the engine
and the native side in a dedicated test, and correct the limitation paragraph
in the documentation accordingly.

Refs #221

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sy8BcM8ivUEpu8uVm7wADn
@lisachenko

Copy link
Copy Markdown
Member Author

@claude need to rebase, or merge master here to update checks in CI pipeline naming

Copy link
Copy Markdown
Member Author

Done — merged master into this branch (merge commit, no rebase), so the renamed CI checks now apply. The full local gate is green after the merge: PHPUnit on 8.5 (13,770 tests) and 8.6.0beta1 (15,001 tests), PHPStan level 10 clean.

Also brought master into the other five open epic branches (#228#232) for the same reason — each validated the same way before pushing.


Generated by Claude Code

@lisachenko
lisachenko marked this pull request as ready for review August 25, 2026 13:27
@lisachenko
lisachenko merged commit 1198be6 into master Aug 25, 2026
7 checks passed
@lisachenko
lisachenko deleted the claude/php86-221-param-doc-comments branch August 25, 2026 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants