# phpstan/phpdoc-parser Guide to PHPDoc AST Parsing

> phpstan/phpdoc-parser turns PHPDoc comments into a modifiable AST for PHPStan and other PHP tooling. It supports modern PHPDoc types, Doctrine annotations, visitor traversal, and format-preserving printing, but it is a parsing library rather than a complete static analyzer.

**phpstan/phpdoc-parser** — Next-gen phpDoc parser with support for intersection types and generics

- Repository: https://github.com/phpstan/phpdoc-parser
- Stars: 1,539 · Forks: 78
- Language: PHP
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/phpstan-phpdoc-parser

## Why phpstan/phpdoc-parser Exists in PHP Tooling

phpstan/phpdoc-parser addresses the gap between PHPDoc comments written for humans and the structured information expected by automated tools. A comment such as `/** @param Lorem $a */` contains a tag, a type, and a parameter name. Treating that entire line as text makes validation, rewriting, and source-aware edits awkward. This library converts it into AST nodes that can be inspected and changed programmatically.

The intended users are PHP developers building tools around PHPDoc, with PHPStan named as the main consumer. A static-analysis tool can inspect `ParamTagValueNode` values, inspect the type node assigned to a parameter, or traverse other nodes through `NodeTraverser`. Another use case is a PHPDoc formatting or migration utility that needs to change one type without rebuilding the complete comment.

This is not a runtime type system. It does not enforce that a PHP function accepts `Lorem`, and the documented workflow parses comments rather than analyzing PHP source files. Doctrine annotations are supported at the syntax level, with AST classes under the `PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine` namespace. The README does not describe annotation execution, reflection, validation against runtime values, or automatic PHPDoc generation. Those capabilities must come from another component.

The format-preserving printer narrows the library's purpose further. When a tool receives an AST, changes a node, and prints the result, it can preserve details such as line structure and comments more closely than a printer that serializes every node from scratch. This is particularly relevant for refactoring tools and diagnostics that should not create unrelated formatting changes.

## From PHPDoc Tokens to Typed AST Nodes

The parsing path has explicit layers. `Lexer` tokenizes a PHPDoc string. `TokenIterator` advances through those tokens, while `TypeParser` and `ConstExprParser` interpret type syntax and constant expressions. `PhpDocParser` combines those components to produce a `PhpDocNode` representing the full comment. This separation matters when integrating the library because callers must construct all four pieces for the documented basic setup.

For `/** @param Lorem $a */`, the README states that `parse()` returns a `PhpDocNode`. Calling `getParamTagValues()` returns `ParamTagValueNode` objects. The first object exposes the parameter name as `$a` and its type as an `IdentifierTypeNode` representing `Lorem`. The value `Lorem` is therefore represented as syntax rather than treated as a PHP class that the parser attempts to load.

The type grammar extends beyond identifiers. Documented forms include nullable types, union and intersection types, generic types, array and object shapes, callables, conditional types, offset access, and constant expressions. `ConstExprParser` covers scalar values, arrays, and class constant fetches such as `ClassName::CONSTANT`. The repository keeps grammars under `doc/grammars` in the format read by the `phplrt` compiler, which gives maintainers a grammar-level description separate from PHP implementation code.

That breadth makes the parser relevant to modern PHPStan syntax, but it should not be confused with semantic acceptance of every type in every context. The README directs users to PHPStan's PHPDoc documentation for the complete supported feature list. Before relying on an edge-case construct, check that documentation and the 2.3.x API reference rather than assuming that any string accepted elsewhere by PHPStan is guaranteed to behave identically in every tool.

## Installing phpstan/phpdoc-parser with Composer

The documented installation path is Composer. Run the following command in the PHP project that needs the library. The resulting `vendor/autoload.php` is used by the README's PHP examples.

```bash
composer require phpstan/phpdoc-parser
```

Composer selects a compatible package version and makes the classes available through the generated autoloader. The README does not provide a manual installation procedure or a standalone PHAR. It also does not state a command for checking the installed version, so do not add an invented `show` command to the tutorial.

A first parse requires several objects. The imports below are the documented parser dependencies; the script also defines the PHPDoc string that the next section parses.

```php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\ParserConfig;
use PHPStan\PhpDocParser\Parser\ConstExprParser;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDocParser\Parser\TypeParser;
```

Create `ParserConfig` with an empty attribute list, pass it to the lexer and both parsers, and then create `PhpDocParser`. This explicit assembly is more involved than calling one façade method, but it exposes the parsing stages that tools may need to control.

```php
$config = new ParserConfig(usedAttributes: []);
$lexer = new Lexer($config);
$constExprParser = new ConstExprParser($config);
$typeParser = new TypeParser($config, $constExprParser);
$phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
```

The empty attribute list is sufficient for the basic inspection example shown in the README. Source positions, token indexes, and comments require a different `ParserConfig`, as described below.

## Reading and Rewriting a Real PHPDoc Comment

Tokenize the source comment, wrap the token list in `TokenIterator`, and pass it to `PhpDocParser`. The documented output exposes parameter tags as structured objects.

```php
$tokens = new TokenIterator($lexer->tokenize('/** @param Lorem $a */'));
$phpDocNode = $phpDocParser->parse($tokens);
$paramTags = $phpDocNode->getParamTagValues();
echo $paramTags[0]->parameterName;
echo $paramTags[0]->type;
```

The parameter name is `$a`, and the type property contains an `IdentifierTypeNode` for `Lorem`. Depending on the caller, the type node can be examined as an AST object rather than immediately printed as a PHP string.

To modify the tree, enable the attributes used by the format-preserving printer and apply `CloningVisitor`. Cloning keeps the original AST available for comparison with the modified tree. The new parameter type is then assigned as an `IdentifierTypeNode`.

```php
$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true, 'comments' => true]);
$lexer = new Lexer($config);
$constExprParser = new ConstExprParser($config);
$typeParser = new TypeParser($config, $constExprParser);
$phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
$tokens = new TokenIterator($lexer->tokenize('/** @param Lorem $a */'));
$phpDocNode = $phpDocParser->parse($tokens);
$cloningTraverser = new NodeTraverser([new CloningVisitor()]);
[$newPhpDocNode] = $cloningTraverser->traverse([$phpDocNode]);
$newPhpDocNode->getParamTagValues()[0]->type = new IdentifierTypeNode('Ipsum');
```

Finally, call `Printer::printFormatPreserving()` with the modified tree, original tree, and original token iterator. The README's example produces `/** @param Ipsum $a */`. This operation is an AST-aware rewrite, not a general-purpose PHP source formatter.

The required `lines`, `indexes`, and `comments` attributes explain why printer setup differs from the basic parser example. Enabling only some attributes would not match the complete configuration documented for format-preserving output.

## Visitor Controls and AST Attributes in phpdoc-parser

The visitor API follows the pattern used by `nikic/PHP-Parser`: a visitor enters nodes, inspects or transforms them, and returns a node. `AbstractNodeVisitor` and `NodeTraverser` support recursive traversal, while `Node` provides the common base type used by the visitor callback.

Traversal is not limited to visiting every descendant. The documented control constants are `DONT_TRAVERSE_CHILDREN`, `STOP_TRAVERSAL`, `REMOVE_NODE`, and `DONT_TRAVERSE_CURRENT_AND_CHILDREN`. These controls make it possible to skip the children of a container node, end a traversal, remove a node from the resulting tree, or stop both at the current node and below it. A tool that edits tag collections should use these documented return values rather than mutating arrays outside the established traversal model.

Node attributes provide a separate capability. `ParserConfig` can request `lines`, `indexes`, and `comments`. Lines and indexes can map AST nodes back to source positions, while comments support formatting-sensitive work. The README specifically states that the format-preserving printer requires these attributes. They are metadata attached during parsing, not replacements for semantic validation.

There is a practical trade-off here. Rich attributes consume more information and require callers to construct a more capable parser configuration. Simple consumers that only inspect tag values can use the empty configuration shown in the basic example. Conversely, a printer should not be given a deliberately incomplete configuration and then expected to retain source details that were never recorded.

## Where phpstan/phpdoc-parser Stops and What Replaces It

The main limitation is scope. This library parses and modifies PHPDoc and Doctrine annotation syntax, but the README does not document semantic type resolution against PHPStan's knowledge of classes, function definitions, or runtime conditions. It also does not claim to analyze executable PHP source, detect runtime type errors, or validate whether a named class exists. Those are different jobs.

The clearest real alternative is `nikic/PHP-Parser`, which the README cites as the inspiration for the visitor and format-preserving printer components. `nikic/PHP-Parser` works with PHP language syntax, whereas `phpstan/phpdoc-parser` works with PHPDoc syntax and its AST. The latter is the appropriate dependency when the input itself is a PHPDoc comment.

PHPStan is another related consumer rather than a drop-in replacement. The README names PHPStan as the main user and links to PHPStan's PHPDoc feature documentation. A project that already runs PHPStan may receive the benefits indirectly. A standalone utility still needs to depend on and configure this parser itself. Conversely, adding PHPStan as a workaround would be unnecessary when the task is limited to parsing and rewriting comments.

Doctrine support also needs careful interpretation. The README confirms that Doctrine annotations can be parsed and identifies their AST namespace. It does not describe executing annotation classes or reproducing Doctrine's object lifecycle. Consumers should treat this as syntax recognition and node construction, not as permission to instantiate annotation classes merely because they appear in a comment.

## Release Cadence, Upgrades, and the MIT License

The repository is not archived, and its last push was on 2026-10-16. Recent releases include `2.3.6` on 2026-09-27, `2.3.5` on 2026-08-31, and `2.3.4` on 2026-08-31. These facts indicate recent activity around the `2.3.x` default branch, but they do not by themselves establish API compatibility for every downstream project.

Upgrade planning should start with `UPGRADING.md`, which is included in the repository. The public API is organized around concrete classes such as `ParserConfig`, `Lexer`, `PhpDocParser`, `NodeTraverser`, and `Printer`, so changes to method signatures, node properties, attributes, or visitor controls can affect custom tooling. The repository also contains `tests/` and static-analysis configuration, but the README does not document a service-level compatibility promise for consumers.

The project is distributed under the MIT License. That is a permissive license with the standard permission and disclaimer structure, but this article does not provide legal advice. A distribution that bundles the library should still inspect the repository `LICENSE`, preserve required notices, and review dependency licenses separately if it packages more than this project.

For maintainers, the `Makefile` exposes `make check`, which combines linting, code-style checks, tests, and PHPStan. Individual targets include `make tests`, `make lint`, `make cs`, and `make phpstan`. These are contributor workflows, not runtime commands that an adopting application needs on every request.

## Conclusion

Adopt phpstan/phpdoc-parser when a PHPStan-based or independent tool must inspect PHPDoc syntax as structured nodes, modify types, or preserve source formatting. Do not choose it for runtime type enforcement, complete PHP code analysis, or annotation execution. Before adoption, verify that every PHPDoc construct used by your project appears in the documented PHPStan type and tag documentation, then inspect `UPGRADING.md` for compatibility with the intended parser version. For a library already using the 2.3.x API, the documented Composer installation and format-preserving printer are the first concrete adoption checks.

## FAQ

### How do I install phpstan/phpdoc-parser?

The README documents `composer require phpstan/phpdoc-parser`. Application code then loads Composer's generated `vendor/autoload.php` and constructs the documented parser components.

### Can phpstan/phpdoc-parser modify PHPDoc types?

Yes. The README shows replacing an `IdentifierTypeNode` and passing the changed AST, original AST, and token iterator to `Printer::printFormatPreserving()`.

### Does phpstan/phpdoc-parser parse Doctrine annotations?

Yes. The README states that Doctrine annotations are supported and places their AST classes under the `PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine` namespace.

## Sources

- [Issues](https://github.com/phpstan/phpdoc-parser/issues)
- [License: MIT](https://github.com/phpstan/phpdoc-parser/blob/2.3.x/LICENSE)
- [phpstan/phpdoc-parser on GitHub](https://github.com/phpstan/phpdoc-parser)
- [README](https://github.com/phpstan/phpdoc-parser/blob/2.3.x/README.md)
- [Releases](https://github.com/phpstan/phpdoc-parser/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/phpstan-phpdoc-parser
