Go to file
2018-06-07 15:06:54 +03:00
comment create ForInitSemicolonToken and ForCondSemicolonToken comment anchors 2018-06-03 12:50:08 +03:00
errors Merge branch 'comments3' 2018-06-07 15:06:54 +03:00
node changing ClosureUse node purpose 2018-06-03 12:38:58 +03:00
parser Merge branch 'comments3' 2018-06-07 15:06:54 +03:00
php5 Merge branch 'comments3' 2018-06-07 15:06:54 +03:00
php7 Merge branch 'comments3' 2018-06-07 15:06:54 +03:00
position refactor tokenString 2018-06-05 15:20:23 +03:00
printer changing ClosureUse node purpose 2018-06-03 12:38:58 +03:00
scanner Merge branch 'comments3' 2018-06-07 15:06:54 +03:00
visitor create ClassExtends ClassImplements InterfaceExtends nodes 2018-06-03 10:50:37 +03:00
walker update package comments 2018-02-20 20:22:15 +02:00
.gitignore added profiling commands to Makefile 2018-06-05 00:09:21 +03:00
CODE_OF_CONDUCT.md update CODE_OF_CONDUCT.md 2018-01-05 19:49:29 +02:00
CONTRIBUTING.md create CONTRIBUTING.md 2018-01-05 19:37:08 +02:00
doc.go issue #8: update readme 2018-04-10 15:51:05 +03:00
ISSUE_TEMPLATE.md Create ISSUE_TEMPLATE.md 2018-01-05 19:23:10 +02:00
LICENSE Create LICENSE 2018-01-02 14:37:19 +02:00
main.go #28 fix race conditions 2018-06-06 19:47:28 +03:00
Makefile #28 fix race conditions 2018-06-06 19:47:28 +03:00
parser.jpg #5 update logo 2018-05-16 09:08:16 +03:00
README.md Merge branch 'comments3' 2018-06-07 15:06:54 +03:00

PHP Parser written in Go

PHP Parser written in Go

Go Report Card Exago Exago GoDoc

Try it online: demo

Features:

  • Fully support PHP 5 and PHP 7 syntax
  • Abstract syntax tree (AST) representation
  • Traversing AST
  • Namespace resolver
  • Able to parse syntax-invalid PHP files

Roadmap

  • Saving comments and empty lines
  • Control Flow Graph (CFG)
  • PhpDocComment parser
  • Stabilize api

Install

go get github.com/z7zmey/php-parser

CLI

php-parser [-php5] <path> ...

Dump AST to stdout.

Example

package main

import (
	"fmt"
	"bytes"
	"os"

	"github.com/z7zmey/php-parser/php7"
	"github.com/z7zmey/php-parser/visitor"
)

func main() {
	src := bytes.NewBufferString(`<? echo "Hello world";`)

	parser := php7.NewParser(src, "example.php")
	parser.Parse()

	for _, e := range parser.GetErrors() {
		fmt.Println(e)
	}

	visitor := visitor.Dumper{
		Writer:    os.Stdout,
		Indent:    "",
		Comments:  parser.GetComments(),
		Positions: parser.GetPositions(),
	}

	rootNode := parser.GetRootNode()
	rootNode.Walk(visitor)
}

Namespace resolver

Namespace resolver is a visitor that resolves nodes fully qualified name and saves into map[node.Node]string structure

  • For Class, Interface, Trait, Function, Constant nodes it saves name with current namespace.
  • For Name, Relative, FullyQualified nodes it resolves use aliases and saves a fully qualified name.

Parsing syntax-invalid PHP files

If we try to parse $a$b; then the parser triggers error 'syntax error: unexpected T_VARIABLE'. Token $b is unexpected, but parser recovers parsing process and returns $b; statement to AST, because it is syntactically correct.

Pretty printer

nodes := &stmt.StmtList{
	Stmts: []node.Node{
		&stmt.Namespace{
			NamespaceName: &name.Name{
				Parts: []node.Node{
					&name.NamePart{Value: "Foo"},
				},
			},
		},
		&stmt.Class{
			Modifiers: []node.Node{
				&node.Identifier{Value: "abstract"},
			},
			ClassName: &name.Name{
				Parts: []node.Node{
					&name.NamePart{Value: "Bar"},
				},
			},
			Extends: &stmt.ClassExtends{
                ClassName: &name.Name{
                    Parts: []node.Node{
                        &name.NamePart{
                            Value: "Baz"
                        },
                    },
                },
            },
			Stmts: []node.Node{
				&stmt.ClassMethod{
					Modifiers: []node.Node{
						&node.Identifier{Value: "public"},
					},
					MethodName: &node.Identifier{Value: "greet"},
					Stmt: &stmt.StmtList{
						Stmts: []node.Node{
							&stmt.Echo{
								Exprs: []node.Node{
									&scalar.String{Value: "'Hello world'"},
								},
							},
						},
					},
				},
			},
		},
	},
}

file := os.Stdout
p := printer.NewPrinter(file, "    ")
p.PrintFile(nodes)

It prints to stdout:

<?php
namespace Foo;
abstract class Bar extends Baz
{
    public function greet()
    {
        echo 'Hello world';
    }
}