Chris@0
|
1 Upgrading from PHP-Parser 2.x to 3.0
|
Chris@0
|
2 ====================================
|
Chris@0
|
3
|
Chris@0
|
4 The backwards-incompatible changes in this release may be summarized as follows:
|
Chris@0
|
5
|
Chris@0
|
6 * The specific details of the node representation have changed in some cases, primarily to
|
Chris@13
|
7 accommodate new PHP 7.1 features.
|
Chris@0
|
8 * There have been significant changes to the error recovery implementation. This may affect you,
|
Chris@0
|
9 if you used the error recovery mode or have a custom lexer implementation.
|
Chris@0
|
10 * A number of deprecated methods were removed.
|
Chris@0
|
11
|
Chris@0
|
12 ### PHP version requirements
|
Chris@0
|
13
|
Chris@0
|
14 PHP-Parser now requires PHP 5.5 or newer to run. It is however still possible to *parse* PHP 5.2,
|
Chris@0
|
15 5.3 and 5.4 source code, while running on a newer version.
|
Chris@0
|
16
|
Chris@0
|
17 ### Changes to the node structure
|
Chris@0
|
18
|
Chris@0
|
19 The following changes are likely to require code changes if the respective nodes are used:
|
Chris@0
|
20
|
Chris@0
|
21 * The `List` subnode `vars` has been renamed to `items` and now contains `ArrayItem`s instead of
|
Chris@0
|
22 plain variables.
|
Chris@0
|
23 * The `Catch` subnode `type` has been renamed to `types` and is now an array of `Name`s.
|
Chris@0
|
24 * The `TryCatch` subnode `finallyStmts` has been replaced with a `finally` subnode that holds an
|
Chris@0
|
25 explicit `Finally` node.
|
Chris@0
|
26 * The `type` subnode on `Class`, `ClassMethod` and `Property` has been renamed to `flags`. The
|
Chris@0
|
27 `type` subnode has retained for backwards compatibility and is populated to the same value as
|
Chris@0
|
28 `flags`. However, writes to `type` will not update `flags` and use of `type` is discouraged.
|
Chris@0
|
29
|
Chris@0
|
30 The following changes are unlikely to require code changes:
|
Chris@0
|
31
|
Chris@0
|
32 * The `ClassConst` constructor changed to accept an additional `flags` subnode.
|
Chris@0
|
33 * The `Trait` constructor now has the same form as the `Class` and `Interface` constructors: It
|
Chris@0
|
34 takes an array of subnodes. Unlike classes/interfaces, traits can only have a `stmts` subnode.
|
Chris@0
|
35 * The `Array` subnode `items` may now contain `null` elements (due to destructuring).
|
Chris@0
|
36 * `void` and `iterable` types are now stored as strings if the PHP 7 parser is used. Previously
|
Chris@0
|
37 these would have been represented as `Name` instances.
|
Chris@0
|
38
|
Chris@0
|
39 ### Changes to error recovery mode
|
Chris@0
|
40
|
Chris@0
|
41 Previously, error recovery mode was enabled by setting the `throwOnError` option to `false` when
|
Chris@0
|
42 creating the parser, while collected errors were retrieved using the `getErrors()` method:
|
Chris@0
|
43
|
Chris@0
|
44 ```php
|
Chris@0
|
45 $lexer = ...;
|
Chris@0
|
46 $parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer, [
|
Chris@0
|
47 'throwOnError' => true,
|
Chris@0
|
48 ]);
|
Chris@0
|
49
|
Chris@0
|
50 $stmts = $parser->parse($code);
|
Chris@0
|
51 $errors = $parser->getErrors();
|
Chris@0
|
52 if ($errors) {
|
Chris@0
|
53 handleErrors($errors);
|
Chris@0
|
54 }
|
Chris@0
|
55 processAst($stmts);
|
Chris@0
|
56 ```
|
Chris@0
|
57
|
Chris@0
|
58 Both the `throwOnError` option and the `getErrors()` method have been removed in PHP-Parser 3.0.
|
Chris@0
|
59 Instead an instance of `ErrorHandler\Collecting` should be passed to the `parse()` method:
|
Chris@0
|
60
|
Chris@0
|
61 ```php
|
Chris@0
|
62 $lexer = ...;
|
Chris@0
|
63 $parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer);
|
Chris@0
|
64
|
Chris@0
|
65 $errorHandler = new ErrorHandler\Collecting;
|
Chris@0
|
66 $stmts = $parser->parse($code, $errorHandler);
|
Chris@0
|
67 if ($errorHandler->hasErrors()) {
|
Chris@0
|
68 handleErrors($errorHandler->getErrors());
|
Chris@0
|
69 }
|
Chris@0
|
70 processAst($stmts);
|
Chris@0
|
71 ```
|
Chris@0
|
72
|
Chris@0
|
73 #### Multiple parser fallback in error recovery mode
|
Chris@0
|
74
|
Chris@0
|
75 As a result of this change, if a `Multiple` parser is used (e.g. through the `ParserFactory` using
|
Chris@0
|
76 `PREFER_PHP7` or `PREFER_PHP5`), it will now return the result of the first *non-throwing* parse. As
|
Chris@0
|
77 parsing never throws in error recovery mode, the result from the first parser will always be
|
Chris@0
|
78 returned.
|
Chris@0
|
79
|
Chris@0
|
80 The PHP 7 parser is a superset of the PHP 5 parser, with the exceptions that `=& new` and
|
Chris@0
|
81 `global $$foo->bar` are not supported (other differences are in representation only). The PHP 7
|
Chris@0
|
82 parser will be able to recover from the error in both cases. For this reason, this change will
|
Chris@0
|
83 likely pass unnoticed if you do not specifically test for this syntax.
|
Chris@0
|
84
|
Chris@0
|
85 It is possible to restore the precise previous behavior with the following code:
|
Chris@0
|
86
|
Chris@0
|
87 ```php
|
Chris@0
|
88 $lexer = ...;
|
Chris@0
|
89 $parser7 = new Parser\Php7($lexer);
|
Chris@0
|
90 $parser5 = new Parser\Php5($lexer);
|
Chris@0
|
91
|
Chris@0
|
92 $errors7 = new ErrorHandler\Collecting();
|
Chris@0
|
93 $stmts7 = $parser7->parse($code, $errors7);
|
Chris@0
|
94 if ($errors7->hasErrors()) {
|
Chris@0
|
95 $errors5 = new ErrorHandler\Collecting();
|
Chris@0
|
96 $stmts5 = $parser5->parse($code, $errors5);
|
Chris@0
|
97 if (!$errors5->hasErrors()) {
|
Chris@0
|
98 // If PHP 7 parse has errors but PHP 5 parse has no errors, use PHP 5 result
|
Chris@0
|
99 return [$stmts5, $errors5];
|
Chris@0
|
100 }
|
Chris@0
|
101 }
|
Chris@0
|
102 // If PHP 7 succeeds or both fail use PHP 7 result
|
Chris@0
|
103 return [$stmts7, $errors7];
|
Chris@0
|
104 ```
|
Chris@0
|
105
|
Chris@0
|
106 #### Error handling in the lexer
|
Chris@0
|
107
|
Chris@0
|
108 In order to support recovery from lexer errors, the signature of the `startLexing()` method changed
|
Chris@0
|
109 to optionally accept an `ErrorHandler`:
|
Chris@0
|
110
|
Chris@0
|
111 ```php
|
Chris@0
|
112 // OLD
|
Chris@0
|
113 public function startLexing($code);
|
Chris@0
|
114 // NEW
|
Chris@0
|
115 public function startLexing($code, ErrorHandler $errorHandler = null);
|
Chris@0
|
116 ```
|
Chris@0
|
117
|
Chris@13
|
118 If you use a custom lexer with overridden `startLexing()` method, it needs to be changed to accept
|
Chris@0
|
119 the extra parameter. The value should be passed on to the parent method.
|
Chris@0
|
120
|
Chris@0
|
121 #### Error checks in node constructors
|
Chris@0
|
122
|
Chris@0
|
123 The constructors of certain nodes used to contain additional checks for semantic errors, such as
|
Chris@0
|
124 creating a try block without either catch or finally. These checks have been moved from the node
|
Chris@0
|
125 constructors into the parser. This allows recovery from such errors, as well as representing the
|
Chris@0
|
126 resulting (invalid) AST.
|
Chris@0
|
127
|
Chris@0
|
128 This means that certain error conditions are no longer checked for manually constructed nodes.
|
Chris@0
|
129
|
Chris@0
|
130 ### Removed methods, arguments, options
|
Chris@0
|
131
|
Chris@0
|
132 The following methods, arguments or options have been removed:
|
Chris@0
|
133
|
Chris@0
|
134 * `Comment::setLine()`, `Comment::setText()`: Create new `Comment` instances instead.
|
Chris@0
|
135 * `Name::set()`, `Name::setFirst()`, `Name::setLast()`, `Name::append()`, `Name::prepend()`:
|
Chris@0
|
136 Use `Name::concat()` in combination with `Name::slice()` instead.
|
Chris@0
|
137 * `Error::getRawLine()`, `Error::setRawLine()`. Use `Error::getStartLine()` and
|
Chris@0
|
138 `Error::setStartLine()` instead.
|
Chris@0
|
139 * `Parser::getErrors()`. Use `ErrorHandler\Collecting` instead.
|
Chris@0
|
140 * `$separator` argument of `Name::toString()`. Use `strtr()` instead, if you really need it.
|
Chris@0
|
141 * `$cloneNodes` argument of `NodeTraverser::__construct()`. Explicitly clone nodes in the visitor
|
Chris@0
|
142 instead.
|
Chris@0
|
143 * `throwOnError` parser option. Use `ErrorHandler\Collecting` instead.
|
Chris@0
|
144
|
Chris@0
|
145 ### Miscellaneous
|
Chris@0
|
146
|
Chris@0
|
147 * The `NameResolver` will now resolve unqualified function and constant names in the global
|
Chris@0
|
148 namespace into fully qualified names. For example `foo()` in the global namespace resolves to
|
Chris@0
|
149 `\foo()`. For names where no static resolution is possible, a `namespacedName` attribute is
|
Chris@0
|
150 added now, containing the namespaced variant of the name.
|
Chris@13
|
151 * All methods on `PrettyPrinter\Standard` are now protected. Previously most of them were public.
|
Chris@0
|
152 The pretty printer should only be invoked using the `prettyPrint()`, `prettyPrintFile()` and
|
Chris@0
|
153 `prettyPrintExpr()` methods.
|
Chris@0
|
154 * The node dumper now prints numeric values that act as enums/flags in a string representation.
|
Chris@0
|
155 If node dumper results are used in tests, updates may be needed to account for this.
|
Chris@0
|
156 * The constants on `NameTraverserInterface` have been moved into the `NameTraverser` class.
|
Chris@0
|
157 * The emulative lexer now directly postprocesses tokens, instead of using `~__EMU__~` sequences.
|
Chris@0
|
158 This changes the protected API of the emulative lexer.
|
Chris@0
|
159 * The `Name::slice()` method now returns `null` for empty slices, previously `new Name([])` was
|
Chris@0
|
160 used. `Name::concat()` now also supports concatenation with `null`.
|