mirror of
https://github.com/danog/PHP-Parser.git
synced 2024-11-30 04:19:30 +01:00
Partial docs update
This commit is contained in:
parent
feb82eed33
commit
3bb874fcec
@ -6,9 +6,66 @@ Upgrading from PHP-Parser 1.x to 2.0
|
|||||||
PHP-Parser now requires PHP 5.4 or newer to run. It is however still possible to *parse* PHP 5.2 and
|
PHP-Parser now requires PHP 5.4 or newer to run. It is however still possible to *parse* PHP 5.2 and
|
||||||
PHP 5.3 source code, while running on a newer version.
|
PHP 5.3 source code, while running on a newer version.
|
||||||
|
|
||||||
###
|
### Creating a parser instance
|
||||||
|
|
||||||
|
Parser instances should now be created through the `ParserFactory`. Old direct instantiation code
|
||||||
|
will not work, because the parser class was renamed.
|
||||||
|
|
||||||
|
Old:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use PhpParser\Parser, PhpParser\Lexer;
|
||||||
|
$parser = new Parser(new Lexer\Emulative);
|
||||||
|
```
|
||||||
|
|
||||||
|
New:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||||
|
```
|
||||||
|
|
||||||
|
The first argument to `ParserFactory` determines how different PHP versions are handled. The
|
||||||
|
possible values are:
|
||||||
|
|
||||||
|
* `ParserFactory::PREFER_PHP7`: Try to parse code as PHP 7. If this fails, try to parse it as PHP 5.
|
||||||
|
* `ParserFactory::PREFER_PHP5`: Try to parse code as PHP 5. If this fails, try to parse it as PHP 7.
|
||||||
|
* `ParserFactory::ONLY_PHP7`: Parse code as PHP 7.
|
||||||
|
* `ParserFactory::ONLY_PHP5`: Parse code as PHP 5.
|
||||||
|
|
||||||
|
For most practical purposes the difference between `PREFER_PHP7` and `PREFER_PHP5` is mainly whether
|
||||||
|
a scalar type hint like `'string'` will be stored as `'string'` (PHP 7) or as `new Name('string')`
|
||||||
|
(PHP 5).
|
||||||
|
|
||||||
|
To use a custom lexer, pass it as the second argument to the `create()` method:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
$lexer = new MyLexer;
|
||||||
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $lexer);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rename of the `PhpParser\Parser` class
|
||||||
|
|
||||||
|
`PhpParser\Parser` is now an interface, which is implemented by `Parser\Php5`, `Parser\Php7` and
|
||||||
|
`Parser\Multiple`. If you use the `ParserFactory` described above to create your parser instance,
|
||||||
|
this change should have no further impact on you.
|
||||||
|
|
||||||
|
### Removal of legacy aliases
|
||||||
|
|
||||||
|
All legacy aliases for classes have been removed. This includes the old non-namespaced `PHPParser_`
|
||||||
|
classes, as well as the classes that had to be renamed for PHP 7 support.
|
||||||
|
|
||||||
|
### Deprecations
|
||||||
|
|
||||||
|
The `set()`, `setFirst()`, `append()` and `prepend()` methods of the `Node\Name` class have been
|
||||||
|
deprecated. Instead `Name::concat()` and `Name->slice()` should be used.
|
||||||
|
|
||||||
### Miscellaneous
|
### Miscellaneous
|
||||||
|
|
||||||
* The `NodeTraverser` no longer clones nodes by default. If you want to restore the old behavior,
|
* The `NodeTraverser` no longer clones nodes by default. If you want to restore the old behavior,
|
||||||
pass `true` to the constructor.
|
pass `true` to the constructor.
|
||||||
|
* The legacy node format has been removed. If you use custom nodes, they are now expected to
|
||||||
|
implement a `getSubNodeNames()` method.
|
||||||
|
* The default value for `Scalar` node constructors was removed. This means that something like
|
||||||
|
`new LNumber()` should be replaced by `new LNumber(0)`.
|
@ -26,13 +26,12 @@ programmatic PHP code analysis are incidentally PHP developers, not C developers
|
|||||||
What can it parse?
|
What can it parse?
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
The parser uses a PHP 5.6 compliant grammar, which is backwards compatible with all PHP version from PHP 5.2
|
The parser supports parsing PHP 5.2-5.6 and PHP 7.
|
||||||
upwards (and maybe older).
|
|
||||||
|
|
||||||
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
|
As the parser is based on the tokens returned by `token_get_all` (which is only able to lex the PHP
|
||||||
version it runs on), additionally a wrapper for emulating new tokens from 5.3, 5.4, 5.5 and 5.6 is provided.
|
version it runs on), additionally a wrapper for emulating new tokens from 5.5, 5.6 and 7.0 is
|
||||||
This allows to parse PHP 5.6 source code running on PHP 5.3, for example. This emulation is very hacky and not
|
provided. This allows to parse PHP 7.0 source code running on PHP 5.4, for example. This emulation
|
||||||
perfect, but it should work well on any sane code.
|
is somewhat hacky and not perfect, but it should work well on any sane code.
|
||||||
|
|
||||||
What output does it produce?
|
What output does it produce?
|
||||||
----------------------------
|
----------------------------
|
||||||
|
@ -6,20 +6,16 @@ This document explains how to use the parser, the pretty printer and the node tr
|
|||||||
Bootstrapping
|
Bootstrapping
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The library needs to register a class autoloader. You can either use the `vendor/autoload.php` file generated by
|
The library needs to register a class autoloader. When using composer, include the usual
|
||||||
Composer or by including the bundled `lib/bootstrap.php` file:
|
`vendor/autoload.php` file (alternatively you can use the bundled `lib/bootstrap.php` file):
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
require 'path/to/PHP-Parser/lib/bootstrap.php';
|
|
||||||
// Or, if you're using Composer:
|
|
||||||
require 'path/to/vendor/autoload.php';
|
require 'path/to/vendor/autoload.php';
|
||||||
```
|
```
|
||||||
|
|
||||||
Additionally you may want to set the `xdebug.max_nesting_level` ini option to a higher value:
|
Additionally you may want to set the `xdebug.max_nesting_level` ini option to a higher value:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
ini_set('xdebug.max_nesting_level', 3000);
|
ini_set('xdebug.max_nesting_level', 3000);
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -28,33 +24,41 @@ This ensures that there will be no errors when traversing highly nested node tre
|
|||||||
Parsing
|
Parsing
|
||||||
-------
|
-------
|
||||||
|
|
||||||
In order to parse some source code you first have to create a `PhpParser\Parser` object, which
|
In order to parse some source code you first have to create a parser instance:
|
||||||
needs to be passed a `PhpParser\Lexer` instance:
|
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\ParserFactory;
|
||||||
|
$parser = new ParserFactory(ParserFactory::PREFER_PHP7);
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
|
||||||
// or
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Use of the emulative lexer is required if you want to parse PHP code from newer versions than the one
|
The factory accepts a kind argument, that determines how different PHP versions are treated:
|
||||||
you're running on. For example it will allow you to parse PHP 5.6 code while running on PHP 5.3.
|
|
||||||
|
Kind | Behavior
|
||||||
|
---------------
|
||||||
|
`ParserFactory::PREFER_PHP7` | Try to parse code as PHP 7. If this fails, try to parse it as PHP 5.
|
||||||
|
`ParserFactory::PREFER_PHP5` | Try to parse code as PHP 5. If this fails, try to parse it as PHP 7.
|
||||||
|
`ParserFactory::ONLY_PHP7` | Parse code as PHP 7.
|
||||||
|
`ParserFactory::ONLY_PHP5` | Parse code as PHP 5.
|
||||||
|
|
||||||
|
Unless you have strong reason to use something else, `PREFER_PHP7` is a reasonable default.
|
||||||
|
|
||||||
|
Many advanced use-cases require configuration or modification of the lexer, which is described in
|
||||||
|
the [lexer documentation](doc/component/Lexer.markdown).
|
||||||
|
|
||||||
Subsequently you can pass PHP code (including the opening `<?php` tag) to the `parse` method in order to
|
Subsequently you can pass PHP code (including the opening `<?php` tag) to the `parse` method in order to
|
||||||
create a syntax tree. If a syntax error is encountered, an `PhpParser\Error` exception will be thrown:
|
create a syntax tree. If a syntax error is encountered, an `PhpParser\Error` exception will be thrown:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\Error;
|
||||||
$code = '<?php // some code';
|
use PhpParser\ParserFactory;
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
$code = '<?php // some code';
|
||||||
|
$parser = new ParserFactory(ParserFactory::PREFER_PHP7);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmts = $parser->parse($code);
|
$stmts = $parser->parse($code);
|
||||||
// $stmts is an array of statement nodes
|
// $stmts is an array of statement nodes
|
||||||
} catch (PhpParser\Error $e) {
|
} catch (Error $e) {
|
||||||
echo 'Parse Error: ', $e->getMessage();
|
echo 'Parse Error: ', $e->getMessage();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -137,11 +141,14 @@ information the formatting is done using a specified scheme. Currently there is
|
|||||||
namely `PhpParser\PrettyPrinter\Standard`.
|
namely `PhpParser\PrettyPrinter\Standard`.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\Error;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
use PhpParser\PrettyPrinter;
|
||||||
|
|
||||||
$code = "<?php echo 'Hi ', hi\\getTarget();";
|
$code = "<?php echo 'Hi ', hi\\getTarget();";
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
$prettyPrinter = new PrettyPrinter\Standard;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// parse
|
// parse
|
||||||
@ -158,7 +165,7 @@ try {
|
|||||||
$code = $prettyPrinter->prettyPrint($stmts);
|
$code = $prettyPrinter->prettyPrint($stmts);
|
||||||
|
|
||||||
echo $code;
|
echo $code;
|
||||||
} catch (PhpParser\Error $e) {
|
} catch (Error $e) {
|
||||||
echo 'Parse Error: ', $e->getMessage();
|
echo 'Parse Error: ', $e->getMessage();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -188,11 +195,13 @@ For this purpose the parser provides a component for traversing and visiting the
|
|||||||
structure of a program using this `PhpParser\NodeTraverser` looks like this:
|
structure of a program using this `PhpParser\NodeTraverser` looks like this:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\NodeTraverser;
|
||||||
|
use PhpParser\ParserFactory;
|
||||||
|
use PhpParser\PrettyPrinter;
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||||
$traverser = new PhpParser\NodeTraverser;
|
$traverser = new NodeTraverser;
|
||||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
$prettyPrinter = new PrettyPrinter\Standard;
|
||||||
|
|
||||||
// add your visitor
|
// add your visitor
|
||||||
$traverser->addVisitor(new MyNodeVisitor);
|
$traverser->addVisitor(new MyNodeVisitor);
|
||||||
@ -218,10 +227,10 @@ try {
|
|||||||
The corresponding node visitor might look like this:
|
The corresponding node visitor might look like this:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
use PhpParser\NodeVisitorAbstract;
|
||||||
|
|
||||||
class MyNodeVisitor extends PhpParser\NodeVisitorAbstract
|
class MyNodeVisitor extends NodeVisitorAbstract
|
||||||
{
|
{
|
||||||
public function leaveNode(Node $node) {
|
public function leaveNode(Node $node) {
|
||||||
if ($node instanceof Node\Scalar\String_) {
|
if ($node instanceof Node\Scalar\String_) {
|
||||||
@ -236,10 +245,12 @@ The above node visitor would change all string literals in the program to `'foo'
|
|||||||
All visitors must implement the `PhpParser\NodeVisitor` interface, which defines the following four
|
All visitors must implement the `PhpParser\NodeVisitor` interface, which defines the following four
|
||||||
methods:
|
methods:
|
||||||
|
|
||||||
public function beforeTraverse(array $nodes);
|
```php
|
||||||
public function enterNode(PhpParser\Node $node);
|
public function beforeTraverse(array $nodes);
|
||||||
public function leaveNode(PhpParser\Node $node);
|
public function enterNode(\PhpParser\Node $node);
|
||||||
public function afterTraverse(array $nodes);
|
public function leaveNode(\PhpParser\Node $node);
|
||||||
|
public function afterTraverse(array $nodes);
|
||||||
|
```
|
||||||
|
|
||||||
The `beforeTraverse()` method is called once before the traversal begins and is passed the nodes the
|
The `beforeTraverse()` method is called once before the traversal begins and is passed the nodes the
|
||||||
traverser was called with. This method can be used for resetting values before traversation or
|
traverser was called with. This method can be used for resetting values before traversation or
|
||||||
@ -299,20 +310,24 @@ assume that no dynamic features are used.
|
|||||||
We start off with the following base code:
|
We start off with the following base code:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\ParserFactory;
|
||||||
|
use PhpParser\PrettyPrinter;
|
||||||
|
use PhpParser\NodeTraverser;
|
||||||
|
use PhpParser\NodeVisitor\NameResolver;
|
||||||
|
|
||||||
$inDir = '/some/path';
|
$inDir = '/some/path';
|
||||||
$outDir = '/some/other/path';
|
$outDir = '/some/other/path';
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
|
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
|
||||||
$traverser = new PhpParser\NodeTraverser;
|
$traverser = new NodeTraverser;
|
||||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
$prettyPrinter = new PrettyPrinter\Standard;
|
||||||
|
|
||||||
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); // we will need resolved names
|
$traverser->addVisitor(new NameResolver); // we will need resolved names
|
||||||
$traverser->addVisitor(new NodeVisitor\NamespaceConverter); // our own node visitor
|
$traverser->addVisitor(new NamespaceConverter); // our own node visitor
|
||||||
|
|
||||||
// iterate over all .php files in the directory
|
// iterate over all .php files in the directory
|
||||||
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($inDir));
|
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($inDir));
|
||||||
$files = new RegexIterator($files, '/\.php$/');
|
$files = new \RegexIterator($files, '/\.php$/');
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
try {
|
try {
|
||||||
@ -343,9 +358,9 @@ Now lets start with the main code, the `NodeVisitor\NamespaceConverter`. One thi
|
|||||||
is convert `A\\B` style names to `A_B` style ones.
|
is convert `A\\B` style names to `A_B` style ones.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
|
||||||
|
class NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||||
{
|
{
|
||||||
public function leaveNode(Node $node) {
|
public function leaveNode(Node $node) {
|
||||||
if ($node instanceof Node\Name) {
|
if ($node instanceof Node\Name) {
|
||||||
@ -366,10 +381,10 @@ only the shortname (i.e. the last part of the name), but they need to contain th
|
|||||||
the namespace prefix:
|
the namespace prefix:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
|
||||||
|
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||||
{
|
{
|
||||||
public function leaveNode(Node $node) {
|
public function leaveNode(Node $node) {
|
||||||
if ($node instanceof Node\Name) {
|
if ($node instanceof Node\Name) {
|
||||||
@ -392,10 +407,10 @@ There is not much more to it than converting the namespaced name to string with
|
|||||||
The last thing we need to do is remove the `namespace` and `use` statements:
|
The last thing we need to do is remove the `namespace` and `use` statements:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
|
|
||||||
|
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
|
||||||
{
|
{
|
||||||
public function leaveNode(Node $node) {
|
public function leaveNode(Node $node) {
|
||||||
if ($node instanceof Node\Name) {
|
if ($node instanceof Node\Name) {
|
||||||
|
@ -17,7 +17,6 @@ Furthermore it is possible to dump nodes into a human readable format using the
|
|||||||
`PhpParser\NodeDumper`. This can be used for debugging.
|
`PhpParser\NodeDumper`. This can be used for debugging.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
|
||||||
$code = <<<'CODE'
|
$code = <<<'CODE'
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
@ -28,7 +27,7 @@ function printLine($msg) {
|
|||||||
printLine('Hello World!!!');
|
printLine('Hello World!!!');
|
||||||
CODE;
|
CODE;
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
|
||||||
$nodeDumper = new PhpParser\NodeDumper;
|
$nodeDumper = new PhpParser\NodeDumper;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -106,7 +105,7 @@ function printLine($msg) {
|
|||||||
printLine('Hello World!!!');
|
printLine('Hello World!!!');
|
||||||
CODE;
|
CODE;
|
||||||
|
|
||||||
$parser = new PhpParser\Parser(new PhpParser\Lexer);
|
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
|
||||||
$serializer = new PhpParser\Serializer\XML;
|
$serializer = new PhpParser\Serializer\XML;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -14,8 +14,11 @@ the following syntactic elements:
|
|||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
use PhpParser\BuilderFactory;
|
||||||
$factory = new PhpParser\BuilderFactory;
|
use PhpParser\PrettyPrinter;
|
||||||
|
use PhpParser\Node;
|
||||||
|
|
||||||
|
$factory = new BuilderFactory;
|
||||||
$node = $factory->namespace('Name\Space')
|
$node = $factory->namespace('Name\Space')
|
||||||
->addStmt($factory->use('Some\Other\Thingy')->as('SomeOtherClass'))
|
->addStmt($factory->use('Some\Other\Thingy')->as('SomeOtherClass'))
|
||||||
->addStmt($factory->class('SomeClass')
|
->addStmt($factory->class('SomeClass')
|
||||||
@ -38,7 +41,7 @@ $node = $factory->namespace('Name\Space')
|
|||||||
->makeProtected() // ->makePublic() [default], ->makePrivate()
|
->makeProtected() // ->makePublic() [default], ->makePrivate()
|
||||||
->addParam($factory->param('someParam')->setDefault('test'))
|
->addParam($factory->param('someParam')->setDefault('test'))
|
||||||
// it is possible to add manually created nodes
|
// it is possible to add manually created nodes
|
||||||
->addStmt(new PhpParser\Node\Expr\Print_(new PhpParser\Node\Expr\Variable('someParam')))
|
->addStmt(new Node\Expr\Print_(new Node\Expr\Variable('someParam')))
|
||||||
)
|
)
|
||||||
|
|
||||||
// properties will be correctly reordered above the methods
|
// properties will be correctly reordered above the methods
|
||||||
@ -50,7 +53,7 @@ $node = $factory->namespace('Name\Space')
|
|||||||
;
|
;
|
||||||
|
|
||||||
$stmts = array($node);
|
$stmts = array($node);
|
||||||
$prettyPrinter = new PhpParser\PrettyPrinter\Standard();
|
$prettyPrinter = new PrettyPrinter\Standard();
|
||||||
echo $prettyPrinter->prettyPrintFile($stmts);
|
echo $prettyPrinter->prettyPrintFile($stmts);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user