Rust PHP Parser
A fast, fault-tolerant PHP parser written in Rust. Produces a full typed AST with source spans, recovers from syntax errors, and covers PHP 7.4–8.5 syntax.
Try the interactive playground → · AST Node Reference →
Installation
[]
= "*"
= "*" # AST types and visitor/fold traits
# Optional
= "*" # pretty-print AST back to PHP source
= "*" # only needed when using parse_arena() directly
Quick Start
use parse;
let result = parse;
println!;
for err in &result.errors
// Resolve byte offsets to line/column
let pos = result.source_map.offset_to_line_col;
parse returns a [ParseResult] with no lifetime parameters — the AST is fully owned and can be stored anywhere.
ParseResult fields
| Field | Type | Description |
|---|---|---|
program |
php_ast::owned::Program |
The parsed AST. Always present, even when errors exist. |
errors |
Vec<ParseError> |
Parse errors and diagnostics. Empty on success. |
errors_truncated |
bool |
true when the error list was capped. |
source |
String |
The original source text. Slice spans: &result.source[span.start as usize..span.end as usize]. |
comments |
Vec<php_ast::owned::Comment> |
All comments in source order, not attached to AST nodes. |
source_map |
SourceMap |
Pre-computed line index for offset_to_line_col. |
Usage
Version-aware parsing
The parser targets PHP 8.5 by default. Use parse_versioned() to target an earlier version:
use ;
let result = parse_versioned;
// Enums require PHP 8.1 — a VersionTooLow diagnostic is emitted.
assert!;
Supported versions: Php74, Php80, Php81, Php82, Php83, Php84, Php85.
Error recovery
The parser never fails — it always produces a complete AST. Unrecoverable statements become StmtKind::Error nodes so the tree is structurally intact:
let result = parse;
assert!;
assert!;
Re-parsing (LSP / editor use)
ParserContext reuses the backing arena in O(1) across repeated parses. reparse_owned() returns a fully-owned ParseResult:
let mut ctx = new;
let a = ctx.reparse_owned;
let b = ctx.reparse_owned; // a stays alive
reparse_versioned and reparse_owned_versioned are also available.
Visitor API
OwnedVisitor works directly on a ParseResult. Override only the node types you care about; the defaults recurse into children automatically:
use ;
use ControlFlow;
let result = parse;
let mut v = VarCounter ;
v.visit_program;
assert_eq!;
Return ControlFlow::Break(()) to stop early. Return ControlFlow::Continue(()) without calling walk_owned_* to skip a subtree.
Use OwnedScopeVisitor + OwnedScopeWalker when you need to know which namespace, class, or function you are currently inside — every visit method receives an OwnedScope. See docs.rs/php-ast for details.
AST transformation
FoldOwned rebuilds the AST, letting you transform specific nodes. Override only what you need; all other nodes are rebuilt identically:
use ;
;
let result = parse;
let transformed = NegateInts.fold_program;
Pretty printer
let result = parse;
let output = pretty_print_owned;
// output == "<?php\necho 1 + 2;"
Use pretty_print_owned_file to append a trailing newline. Pass a PrinterConfig for custom indentation:
use ;
let config = PrinterConfig ;
let output = pretty_print_owned_with_config;
To preserve comments:
let output = pretty_print_owned_with_comments;
PHPDoc parser
use ;
let doc = parse;
for param in find_tags
Arena API
For maximum throughput or when you already hold an ArenaParseResult (e.g. inside an LSP hot path), use parse_arena() and the arena-form Visitor / Fold / pretty_print functions. See docs.rs/php-ast for the arena visitor and fold traits.
Architecture
Source flows through Lexer → Parser → arena-allocated AST nodes. The lexer is lazy (tokens produced on demand with peeking slots); the parser is Pratt-based recursive descent with panic-mode error recovery. The owned AST (php_ast::owned) provides lifetime-free mirrors of every node type for storage and manipulation without arena lifetime constraints.
Performance
The fastest full-featured PHP parser. Optimised for modern PHP applications with full typing (PHP 7.4+, 8.x). For comparative benchmarks against other PHP parsers see php-parser-benchmark.
Contributing
See CONTRIBUTING.md for build instructions, testing, and contributor guides.
Acknowledgements
Inspired by and indebted to nikic/PHP-Parser — test corpus fixtures were adapted from its test suite. Thanks to the PHP community contributors.
License
BSD 3-Clause