Chris@13
|
1 Pretty printing
|
Chris@13
|
2 ===============
|
Chris@13
|
3
|
Chris@13
|
4 Pretty printing is the process of converting a syntax tree back to PHP code. In its basic mode of
|
Chris@13
|
5 operation the pretty printer provided by this library will print the AST using a certain predefined
|
Chris@13
|
6 code style and will discard (nearly) all formatting of the original code. Because programmers tend
|
Chris@13
|
7 to be rather picky about their code formatting, this mode of operation is not very suitable for
|
Chris@13
|
8 refactoring code, but can be used for automatically generated code, which is usually only read for
|
Chris@13
|
9 debugging purposes.
|
Chris@13
|
10
|
Chris@13
|
11 Basic usage
|
Chris@13
|
12 -----------
|
Chris@13
|
13
|
Chris@13
|
14 ```php
|
Chris@13
|
15 $stmts = $parser->parse($code);
|
Chris@13
|
16
|
Chris@13
|
17 // MODIFY $stmts here
|
Chris@13
|
18
|
Chris@13
|
19 $prettyPrinter = new PhpParser\PrettyPrinter\Standard;
|
Chris@13
|
20 $newCode = $prettyPrinter->prettyPrintFile($stmts);
|
Chris@13
|
21 ```
|
Chris@13
|
22
|
Chris@13
|
23 The pretty printer has three basic printing methods: `prettyPrint()`, `prettyPrintFile()` and
|
Chris@13
|
24 `prettyPrintExpr()`. The one that is most commonly useful is `prettyPrintFile()`, which takes an
|
Chris@13
|
25 array of statements and produces a full PHP file, including opening `<?php`.
|
Chris@13
|
26
|
Chris@13
|
27 `prettyPrint()` also takes a statement array, but produces code which is valid inside an already
|
Chris@13
|
28 open `<?php` context. Lastly, `prettyPrintExpr()` takes an `Expr` node and prints only a single
|
Chris@13
|
29 expression.
|
Chris@13
|
30
|
Chris@13
|
31 Customizing the formatting
|
Chris@13
|
32 --------------------------
|
Chris@13
|
33
|
Chris@13
|
34 Apart from an `shortArraySyntax` option, the default pretty printer does not provide any
|
Chris@13
|
35 functionality to customize the formatting of the generated code. The pretty printer does respect a
|
Chris@13
|
36 number of `kind` attributes used by some notes (e.g., whether an integer should be printed as
|
Chris@13
|
37 decimal, hexadecimal, etc), but there are no options to control brace placement or similar.
|
Chris@13
|
38
|
Chris@13
|
39 If you want to make minor changes to the formatting, the easiest way is to extend the pretty printer
|
Chris@13
|
40 and override the methods responsible for the node types you are interested in.
|
Chris@13
|
41
|
Chris@13
|
42 If you want to have more fine-grained formatting control, the recommended method is to combine the
|
Chris@13
|
43 default pretty printer with an existing library for code reformatting, such as
|
Chris@13
|
44 [PHP-CS-Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer).
|
Chris@13
|
45
|
Chris@13
|
46 Formatting-preserving pretty printing
|
Chris@13
|
47 -------------------------------------
|
Chris@13
|
48
|
Chris@13
|
49 > **Note:** This functionality is **experimental** and not yet complete.
|
Chris@13
|
50
|
Chris@13
|
51 For automated code refactoring, migration and similar, you will usually only want to modify a small
|
Chris@13
|
52 portion of the code and leave the remainder alone. The basic pretty printer is not suitable for
|
Chris@13
|
53 this, because it will also reformat parts of the code which have not been modified.
|
Chris@13
|
54
|
Chris@13
|
55 Since PHP-Parser 4.0, an experimental formatting-preserving pretty-printing mode is available, which
|
Chris@13
|
56 attempts to preserve the formatting of code (those AST nodes that have not changed) and only reformat
|
Chris@13
|
57 code which has been modified or newly inserted.
|
Chris@13
|
58
|
Chris@13
|
59 Use of the formatting-preservation functionality requires some additional preparatory steps:
|
Chris@13
|
60
|
Chris@13
|
61 ```php
|
Chris@13
|
62 use PhpParser\{Lexer, NodeTraverser, NodeVisitor, Parser, PrettyPrinter};
|
Chris@13
|
63
|
Chris@13
|
64 $lexer = new Lexer\Emulative([
|
Chris@13
|
65 'usedAttributes' => [
|
Chris@13
|
66 'comments',
|
Chris@13
|
67 'startLine', 'endLine',
|
Chris@13
|
68 'startTokenPos', 'endTokenPos',
|
Chris@13
|
69 ],
|
Chris@13
|
70 ]);
|
Chris@13
|
71 $parser = new Parser\Php7($lexer);
|
Chris@13
|
72
|
Chris@13
|
73 $traverser = new NodeTraverser();
|
Chris@13
|
74 $traverser->addVisitor(new NodeVisitor\CloningVisitor());
|
Chris@13
|
75
|
Chris@13
|
76 $printer = new PrettyPrinter\Standard();
|
Chris@13
|
77
|
Chris@13
|
78 $oldStmts = $parser->parse($code);
|
Chris@13
|
79 $oldTokens = $lexer->getTokens();
|
Chris@13
|
80
|
Chris@13
|
81 $newStmts = $traverser->traverse($oldStmts);
|
Chris@13
|
82
|
Chris@13
|
83 // MODIFY $newStmts HERE
|
Chris@13
|
84
|
Chris@13
|
85 $newCode = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
|
Chris@13
|
86 ```
|
Chris@13
|
87
|
Chris@13
|
88 If you make use of the name resolution functionality, you will likely want to disable the
|
Chris@13
|
89 `replaceNodes` option. This will add resolved names as attributes, instead of directlying modifying
|
Chris@13
|
90 the AST and causing spurious changes to the pretty printed code. For more information, see the
|
Chris@13
|
91 [name resolution documentation](Name_resolution.markdown).
|
Chris@13
|
92
|
Chris@13
|
93 This functionality is experimental and not yet fully implemented. It should not provide incorrect
|
Chris@13
|
94 code, but it may sometimes reformat more code than necessary. Open issues are tracked in
|
Chris@13
|
95 [issue #344](https://github.com/nikic/PHP-Parser/issues/344). If you encounter problems while using
|
Chris@13
|
96 this functionality, please open an issue, so we know what to prioritize.
|