Adopt an external docblock parser (phpstan/phpdoc-parser or equivalent) behind a source-blind ParsedDocblock utility.
Prep for the SymbolInfo restructure (#542) and the #520 rewrite.
Motivation
Two prior attempts to add docblock-supplemented typing tied the docblock reader to the source path that produced the symbol. The clean split is: docblock reading is source-specific (an AST node exposes getDocComment(), a ReflectionClass exposes its own, a stub file exposes raw text); docblock parsing is source-blind. This issue introduces the source-blind side.
Shape
Pick one existing PHP docblock parser. phpstan/phpdoc-parser is the closest thing the ecosystem has to a shared standard and supports every tag surface the LSP eventually needs (@param, @return, @var, @template, generics, unions, intersections, nullable, keyed arrays, @method and @property). Alternatives welcome; the choice is scoped to this issue.
Wrap the chosen library behind our own types. Domain\Docblock\ParsedDocblock is a value shape we own; consumers hold ParsedDocblock, not the library's node types. The parser is a service: Domain\Docblock\DocblockParserInterface with one implementation wrapping the library, injected by the composition root. No static entry point.
Signature:
interface DocblockParserInterface
{
public function parse(string $text, NameContext $context): ParsedDocblock;
}
NameContext is the same one Resolution\NameContext already owns: the namespace and three import tables in effect at the docblock's location. The parser uses it to resolve @param Foo $x into a ClassName at parse time; consumers do no further resolution.
Limitation to record: a reflected symbol has a declaring namespace but no import table, so its NameContext resolves only fully qualified and same-namespace names. #520's parity coverage must account for that.
ParsedDocblock's field shape is settled in #542. Everything typed: no raw strings for types, no untyped tag lists.
No consumers change in this issue.
Tightening
disallowedMethodCalls restricts PhpParser\Comment\Doc::getText() and the corresponding raw-string reads on the Reflection classes to the parser implementation's file. The reads exist today scattered through HasSymbolLocationTrait and DeclarationSymbolInfoFactory; the restriction comes with the concentration. The human makes the rule edit.
Done
Domain\Docblock\ParsedDocblock, Domain\Docblock\DocblockParserInterface, and one implementation exist.
- One external library dependency added via composer.
- Raw docblock text reads are restricted to the new file.
- No consumers wired yet.
composer test green.
Issue body drafted by AI.
Adopt an external docblock parser (phpstan/phpdoc-parser or equivalent) behind a source-blind
ParsedDocblockutility.Prep for the
SymbolInforestructure (#542) and the #520 rewrite.Motivation
Two prior attempts to add docblock-supplemented typing tied the docblock reader to the source path that produced the symbol. The clean split is: docblock reading is source-specific (an AST node exposes
getDocComment(), aReflectionClassexposes its own, a stub file exposes raw text); docblock parsing is source-blind. This issue introduces the source-blind side.Shape
Pick one existing PHP docblock parser. phpstan/phpdoc-parser is the closest thing the ecosystem has to a shared standard and supports every tag surface the LSP eventually needs (
@param,@return,@var,@template, generics, unions, intersections, nullable, keyed arrays,@methodand@property). Alternatives welcome; the choice is scoped to this issue.Wrap the chosen library behind our own types.
Domain\Docblock\ParsedDocblockis a value shape we own; consumers holdParsedDocblock, not the library's node types. The parser is a service:Domain\Docblock\DocblockParserInterfacewith one implementation wrapping the library, injected by the composition root. No static entry point.Signature:
NameContextis the same oneResolution\NameContextalready owns: the namespace and three import tables in effect at the docblock's location. The parser uses it to resolve@param Foo $xinto aClassNameat parse time; consumers do no further resolution.Limitation to record: a reflected symbol has a declaring namespace but no import table, so its
NameContextresolves only fully qualified and same-namespace names. #520's parity coverage must account for that.ParsedDocblock's field shape is settled in #542. Everything typed: no raw strings for types, no untyped tag lists.No consumers change in this issue.
Tightening
disallowedMethodCallsrestrictsPhpParser\Comment\Doc::getText()and the corresponding raw-string reads on the Reflection classes to the parser implementation's file. The reads exist today scattered throughHasSymbolLocationTraitandDeclarationSymbolInfoFactory; the restriction comes with the concentration. The human makes the rule edit.Done
Domain\Docblock\ParsedDocblock,Domain\Docblock\DocblockParserInterface, and one implementation exist.composer testgreen.Issue body drafted by AI.