Library / SDK
glayzzle/php-parser avatar
glayzzle/php-parser

php-parser: a PHP lexer and AST parser written in JavaScript

NodeJS PHP Parser - extract AST or tokens

564 stars75 forksJavaScriptBSD-3-Clause

At a glance

What is it?
php-parser is a Node.js library that parses PHP source into an AST or into a token list, with options for PHP 7 mode, doc comment extraction and source positions, and it ships a browser build and TypeScript definitions. It is BSD-3 licensed, and it is the parsing layer that a range of PHP tooling projects build on.
Who is it for?
php-parser fits a JavaScript or TypeScript tool that has to read PHP source, whether for static analysis, formatting, transpilation or inspection, and it is a reasonable choice when you want the AST in the same process as the rest of your tooling rather than shelling out to a PHP binary. It does not fit a project that needs to execute PHP, and it is not the right tool if you already have a PHP process you can query.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What php-parser produces and who reaches for it

php-parser is a JavaScript library that parses PHP code and converts it to an AST. The package description is more specific: parse PHP code from JS and return its AST, with the npm version and download badges on the package page and a Gitter room for chat.

The output has two shapes, and the library is useful for either. The first is a full syntax tree, a program node with children, where every construct is a node with a kind and its own properties. The second is a token list, and the documentation says it is the same as the PHP token_get_all function, so a project that has used PHP's own tokenizer can move to this one and keep the shape of the data.

That combination is why the project has a wide set of dependents. A formatter needs the tree, a linter needs the tree with positions, a transpiler needs the tree, and a rewriter needs to emit code back out.

The listed related projects show the range. There is a Prettier plugin for PHP, a Babel preset that converts PHP syntax to JavaScript and can run a subset of PHP in the browser or in Node.js, a tool to generate pot files for WordPress plugins and themes, a PHP intellisense and code completion project for VS Code, a unparser that produces code in the style PSR-1 and PSR-2 recommend, a php-writer project that updates PHP scripts from their AST, a TypeScript project providing PHP code inspections, a reflection API for PHP files, a VS Code phpunit extension, and a Lua to PHP transpiler on npm.

So the audience is JavaScript and TypeScript developers who need to read PHP, and the project asks others to open an issue to be added to that list.

Installing and running the first parse

The library is distributed with npm:

bash
npm install php-parser --save

The usage example in the documentation sets up the parser factory and shows the three ways to get output from it:

js
// initialize the php parser factory class
const fs = require("fs");
const path = require("path");
const engine = require("php-parser");

// initialize a new parser instance
const parser = new engine({
  // some options :
  parser: {
    extractDoc: true,
    php7: true,
  },
  ast: {
    withPositions: true,
  },
});

// Retrieve the AST from the specified source
const eval = parser.parseEval('echo "Hello World";');

// Retrieve an array of tokens (same as php function token_get_all)
const tokens = parser.tokenGetAll('<?php echo "Hello World";');

// Load a static file (Note: this file should exist on your computer)
const phpFile = fs.readFileSync("./example.php");

// Log out results
console.log("Eval parse:", eval);
console.log("Tokens parse:", tokens);
console.log("File parse:", parser.parseCode(phpFile));

Three things are worth pulling out of that block.

The options are namespaced into groups. The parser group holds extractDoc, which pulls doc comments out of the source, and php7, which switches the grammar. The ast group holds withPositions, which adds source location information to the nodes. A tool that wants to report an error at a line and column needs withPositions, and a tool that wants to generate documentation from doc blocks needs extractDoc.

The two parse modes are the second point. parseEval parses code in eval style, meaning without the PHP open tags, and parseCode parses code that uses PHP open tags and takes a filename as its second argument. The token list has its own entry point, tokenGetAll, which takes the same kind of input.

The third point is the file handling. parseCode accepts a string or a Buffer, and the example reads the file with fs.readFileSync and passes the Buffer straight in, so you do not have to decode it yourself.

The AST shape and the options that change it

The sample output shows the shape of the tree, and it is a plain JavaScript object with a kind on every node.

js
{
  'kind': 'program',
  'children': [
    {
      'kind': 'echo',
      'arguments': [
        {
          'kind': 'string',
          'isDoubleQuote': true,
          'value': 'Hello World'
        }
      ]
    }
  ]
}

The root is a program node with children, each child is a node for a construct, in this case an echo node with an arguments array, and the argument is a string node carrying isDoubleQuote and value.

Two details here matter for anyone writing a consumer. The kind is a plain string, so switching on it is straightforward. And the string node keeps isDoubleQuote, which means a tool that rewrites code can preserve the original quoting rather than normalising everything to one style.

The options are documented separately on a wiki page, and the two that appear in the example are only the most visible ones. The project points at a list of options that change the behaviour of the parser and the lexer, so a tool with a specific requirement, for example around how a particular construct is represented, should read that list rather than discovering the behaviour by trial.

The documentation links to the AST node definition, which is the reference to keep open while writing a consumer, since the tree is the contract.

The browser build, the online demo and the sandbox

Three things let you look at the output without setting anything up.

There is an online demo at glayzzle.com/php-parser, and the project points at AST Explorer as another way to try it, which is the standard tool for inspecting a syntax tree interactively.

Then there is the package structure. The manifest lists main as src/index.js and browser as dist/php-parser.js, and the files field publishes src, dist, types.d.ts and LICENSE. The browser entry point is a webpack bundle, and there is a webpack.config.js and a babel.config.js in the tree to build it. The scripts show how: build runs webpack with that config, and there is a separate build-docs target that runs jsdoc, and a build-types target that generates the TypeScript definitions from the JSDoc comments with tsd-jsdoc and then formats them with prettier.

That last point is the one that matters for a TypeScript consumer. The types are generated from the JSDoc annotations in the source rather than written by hand, and the published types.d.ts is what the types field points at. So a type error in the definitions is usually a documentation error in the source, and the generated definitions track the source rather than a separately maintained file.

The documentation also lists a Sandbox page, which is the web playground for trying the parser without writing any code.

How the project is tested and released

The repository layout shows a project with a fairly complete toolchain for a library of this kind.

Testing is jest, with the test script running jest and a jest.config.js in the tree. Coverage is tracked with coveralls through a.coveralls.yml file, and there is an.istanbul.yml for the coverage configuration, plus a.codeclimate.yml for static analysis reporting. Linting is eslint with a flat config in eslint.config.mjs, and there is a.husky/ directory with a prepare script that installs the git hooks, and a.yarnrc.yml file, so the project uses yarn for its own tooling even though the library is consumed through npm.

The release process is documented in a RELEASE.md file, which is unusual to find and worth reading before you rely on a version. The publish path is guarded by a prepublishOnly script that runs the build, and the build itself has a prebuild step that runs the tests, so a release cannot ship without the test suite passing.

The release history shows a steady 3.x line: v3.5.1 on 2026-03-29, v3.6.0 on 2026-05-17 and v3.7.0 on 2026-06-10, and the current manifest version is 3.7.0. The repository is not archived, and the last push was on 2026-10-21, so the tree is days old relative to today.

There is also a benchmark script, node test/benchmark.js, and a tutorials/ directory in the tree, so performance work and written guidance are part of the project rather than an afterthought.

Where php-parser is the wrong choice

The first limit is that it reads PHP, it does not run it. This is a parser and lexer, so it can tell you what a file contains, and it cannot tell you what the code does when executed, which is what you need for dynamic behaviour, side effects or anything resolved at runtime.

The second is the version question, and it is a real one. The example enables php7 as a parser option, and the package keywords list php5, php7 and php8. A parser has to track the language versions it accepts, and a codebase that has moved past what a given release handles will fail in ways you need to test for rather than assume.

The third is that a static tree is a snapshot of the source, and the ecosystem around it reflects that. The related projects list includes a unparser that produces code in the style PSR-1 and PSR-2 recommend, which tells you that round tripping PHP through this tree is possible but that the formatting of the result is a separate problem with its own conventions. If your requirement is a formatter, that is a different project with different expectations.

The fourth is the alternative architecture. If you already have PHP in your pipeline, a PHP based parser, or the tokenizer in PHP itself, gives you the same information in the same process as the code that needs it, with no serialisation across a language boundary. The difference in approach is that php-parser moves the parsing into JavaScript, which is the right call when your tooling is JavaScript, and the wrong one when it introduces a second runtime into a pipeline that did not need one.

Licence, maintenance and what to check before you depend on it

php-parser is released under the BSD-3 license clause, with the licence field in the package manifest set to BSD-3-Clause and the text in the LICENSE file. The BSD 3 clause terms are permissive, with the usual attribution and disclaimer, which is a comfortable fit for both commercial tooling and open source projects, and you should read the LICENSE file yourself for the exact wording.

The project is a long lived one, with the current version at 3.7.0 and the 3.x line running through 2026. The repository is not archived and the last push was on 2026-10-02, so the tree is a few weeks old relative to today. There is a CHANGELOG.md and a RELEASE.md in the tree, and a CONTRIBUTING.md and a CODE_OF_CONDUCT.md, so the project has the governance files you would expect of a dependency other people build on.

What to check before you depend on it is specific. Look at the options list in the documentation, because the behaviour of the parser and the lexer is configurable and your consumer probably needs the two options the example shows, extractDoc and withPositions, plus whatever your specific use case requires. Then run the parser over your own code, not a small sample, and check that the constructs your project uses are represented the way you expect, since the AST node definition is the contract and it is large.

If you are shipping this in a browser, the dist bundle is the artefact to check, and the online demo is the fastest way to see whether the tree is what your tool needs before you write any integration code.

Editorial conclusion

php-parser fits a JavaScript or TypeScript tool that has to read PHP source, whether for static analysis, formatting, transpilation or inspection, and it is a reasonable choice when you want the AST in the same process as the rest of your tooling rather than shelling out to a PHP binary. It does not fit a project that needs to execute PHP, and it is not the right tool if you already have a PHP process you can query. Before you adopt it, check the PHP version coverage against the code you need to parse, read the options list, and try the browser build or the online demo on your own source before wiring it into a pipeline.

Frequently asked questions

What does php-parser do?

It is a JavaScript library that parses PHP code and converts it to an AST, and it can also return a list of all tokens for a given input, the same as the PHP token_get_all function. The package description is parse PHP code from JS and return its AST.

How do I install php-parser?

The library is distributed with npm, so npm install php-parser --save. You then create an engine instance, optionally with parser options such as extractDoc and php7 and ast options such as withPositions, and call parseEval, parseCode or tokenGetAll on it.

What is the difference between parseEval and parseCode in php-parser?

parseEval parses PHP code in eval style mode, without the PHP open tags, while parseCode parses code that uses PHP open tags and takes a filename as its second argument. Both accept a string or a Buffer, so a file read with fs.readFileSync can be passed straight in.

Can php-parser run in a browser?

Yes. The package manifest lists a browser entry point of dist/php-parser.js built with webpack, and there is an online demo at glayzzle.com/php-parser plus a Sandbox page in the documentation. The published TypeScript definitions are generated from the JSDoc comments in the source.

What licence does php-parser use?

It is released under the BSD-3 license clause, with the licence field in the package manifest set to BSD-3-Clause and the text in the LICENSE file. The current version is 3.7.0, released on 2026-06-10, and the last push was on 2026-10-21.

Official sources

  1. glayzzle/php-parser on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/glayzzle-php-parser.svg)](https://hysenlabs.com/projects/glayzzle-php-parser)

Was this useful?