1
0
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:
Nikita Popov 2015-07-14 19:19:32 +02:00
parent feb82eed33
commit 3bb874fcec
5 changed files with 133 additions and 60 deletions

View File

@ -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 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
* The `NodeTraverser` no longer clones nodes by default. If you want to restore the old behavior,
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)`.

View File

@ -26,13 +26,12 @@ programmatic PHP code analysis are incidentally PHP developers, not C developers
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
upwards (and maybe older).
The parser supports parsing PHP 5.2-5.6 and PHP 7.
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.
This allows to parse PHP 5.6 source code running on PHP 5.3, for example. This emulation is very hacky and not
perfect, but it should work well on any sane code.
version it runs on), additionally a wrapper for emulating new tokens from 5.5, 5.6 and 7.0 is
provided. This allows to parse PHP 7.0 source code running on PHP 5.4, for example. This emulation
is somewhat hacky and not perfect, but it should work well on any sane code.
What output does it produce?
----------------------------

View File

@ -6,20 +6,16 @@ This document explains how to use the parser, the pretty printer and the node tr
Bootstrapping
-------------
The library needs to register a class autoloader. You can either use the `vendor/autoload.php` file generated by
Composer or by including the bundled `lib/bootstrap.php` file:
The library needs to register a class autoloader. When using composer, include the usual
`vendor/autoload.php` file (alternatively you can use the bundled `lib/bootstrap.php` file):
```php
<?php
require 'path/to/PHP-Parser/lib/bootstrap.php';
// Or, if you're using Composer:
require 'path/to/vendor/autoload.php';
```
Additionally you may want to set the `xdebug.max_nesting_level` ini option to a higher value:
```php
<?php
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
-------
In order to parse some source code you first have to create a `PhpParser\Parser` object, which
needs to be passed a `PhpParser\Lexer` instance:
In order to parse some source code you first have to create a parser instance:
```php
<?php
$parser = new PhpParser\Parser(new PhpParser\Lexer);
// or
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
use PhpParser\ParserFactory;
$parser = new ParserFactory(ParserFactory::PREFER_PHP7);
```
Use of the emulative lexer is required if you want to parse PHP code from newer versions than the one
you're running on. For example it will allow you to parse PHP 5.6 code while running on PHP 5.3.
The factory accepts a kind argument, that determines how different PHP versions are treated:
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
create a syntax tree. If a syntax error is encountered, an `PhpParser\Error` exception will be thrown:
```php
<?php
$code = '<?php // some code';
use PhpParser\Error;
use PhpParser\ParserFactory;
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
$code = '<?php // some code';
$parser = new ParserFactory(ParserFactory::PREFER_PHP7);
try {
$stmts = $parser->parse($code);
// $stmts is an array of statement nodes
} catch (PhpParser\Error $e) {
} catch (Error $e) {
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`.
```php
<?php
use PhpParser\Error;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
$code = "<?php echo 'Hi ', hi\\getTarget();";
$parser = new PhpParser\Parser(new PhpParser\Lexer);
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$prettyPrinter = new PrettyPrinter\Standard;
try {
// parse
@ -158,7 +165,7 @@ try {
$code = $prettyPrinter->prettyPrint($stmts);
echo $code;
} catch (PhpParser\Error $e) {
} catch (Error $e) {
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:
```php
<?php
use PhpParser\NodeTraverser;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
$traverser = new PhpParser\NodeTraverser;
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$traverser = new NodeTraverser;
$prettyPrinter = new PrettyPrinter\Standard;
// add your visitor
$traverser->addVisitor(new MyNodeVisitor);
@ -218,10 +227,10 @@ try {
The corresponding node visitor might look like this:
```php
<?php
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
class MyNodeVisitor extends PhpParser\NodeVisitorAbstract
class MyNodeVisitor extends NodeVisitorAbstract
{
public function leaveNode(Node $node) {
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
methods:
```php
public function beforeTraverse(array $nodes);
public function enterNode(PhpParser\Node $node);
public function leaveNode(PhpParser\Node $node);
public function enterNode(\PhpParser\Node $node);
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
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:
```php
<?php
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\NameResolver;
$inDir = '/some/path';
$outDir = '/some/other/path';
$parser = new PhpParser\Parser(new PhpParser\Lexer\Emulative);
$traverser = new PhpParser\NodeTraverser;
$prettyPrinter = new PhpParser\PrettyPrinter\Standard;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$traverser = new NodeTraverser;
$prettyPrinter = new PrettyPrinter\Standard;
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver); // we will need resolved names
$traverser->addVisitor(new NodeVisitor\NamespaceConverter); // our own node visitor
$traverser->addVisitor(new NameResolver); // we will need resolved names
$traverser->addVisitor(new NamespaceConverter); // our own node visitor
// iterate over all .php files in the directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($inDir));
$files = new RegexIterator($files, '/\.php$/');
$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($inDir));
$files = new \RegexIterator($files, '/\.php$/');
foreach ($files as $file) {
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.
```php
<?php
use PhpParser\Node;
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
class NamespaceConverter extends \PhpParser\NodeVisitorAbstract
{
public function leaveNode(Node $node) {
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:
```php
<?php
use PhpParser\Node;
use PhpParser\Node\Stmt;
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
{
public function leaveNode(Node $node) {
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:
```php
<?php
use PhpParser\Node;
use PhpParser\Node\Stmt;
class NodeVisitor_NamespaceConverter extends PhpParser\NodeVisitorAbstract
class NodeVisitor_NamespaceConverter extends \PhpParser\NodeVisitorAbstract
{
public function leaveNode(Node $node) {
if ($node instanceof Node\Name) {

View File

@ -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.
```php
<?php
$code = <<<'CODE'
<?php
@ -28,7 +27,7 @@ function printLine($msg) {
printLine('Hello World!!!');
CODE;
$parser = new PhpParser\Parser(new PhpParser\Lexer);
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
$nodeDumper = new PhpParser\NodeDumper;
try {
@ -106,7 +105,7 @@ function printLine($msg) {
printLine('Hello World!!!');
CODE;
$parser = new PhpParser\Parser(new PhpParser\Lexer);
$parser = (new PhpParser\ParserFactory)->create(PhpParser\ParserFactory::PREFER_PHP7);
$serializer = new PhpParser\Serializer\XML;
try {

View File

@ -14,8 +14,11 @@ the following syntactic elements:
Here is an example:
```php
<?php
$factory = new PhpParser\BuilderFactory;
use PhpParser\BuilderFactory;
use PhpParser\PrettyPrinter;
use PhpParser\Node;
$factory = new BuilderFactory;
$node = $factory->namespace('Name\Space')
->addStmt($factory->use('Some\Other\Thingy')->as('SomeOtherClass'))
->addStmt($factory->class('SomeClass')
@ -38,7 +41,7 @@ $node = $factory->namespace('Name\Space')
->makeProtected() // ->makePublic() [default], ->makePrivate()
->addParam($factory->param('someParam')->setDefault('test'))
// 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
@ -50,7 +53,7 @@ $node = $factory->namespace('Name\Space')
;
$stmts = array($node);
$prettyPrinter = new PhpParser\PrettyPrinter\Standard();
$prettyPrinter = new PrettyPrinter\Standard();
echo $prettyPrinter->prettyPrintFile($stmts);
```