|
1 | 1 | Upgrading from PHP-Parser 2.x to 3.0
|
2 | 2 | ====================================
|
3 | 3 |
|
4 |
| -This version does not include any major API changes. Only specific details of the node |
5 |
| -representation have changed in some cases. |
| 4 | +The backwards-incompatible changes in this release may be summarized as follows: |
| 5 | + |
| 6 | + * The specific details of the node representation have changed in some cases, primarily to |
| 7 | + accomodate new PHP 7.1 features. |
| 8 | + * There have been significant changes to the error recovery implementation. This may affect you, |
| 9 | + if you used the error recovery mode or have a custom lexer implementation. |
| 10 | + * A number of deprecated methods were removed. |
6 | 11 |
|
7 | 12 | ### PHP version requirements
|
8 | 13 |
|
@@ -31,18 +36,119 @@ The following changes are unlikely to require code changes:
|
31 | 36 | * `void` and `iterable` types are now stored as strings if the PHP 7 parser is used. Previously
|
32 | 37 | these would have been represented as `Name` instances.
|
33 | 38 |
|
34 |
| -### Removed methods |
| 39 | +### Changes to error recovery mode |
| 40 | + |
| 41 | +Previously, error recovery mode was enabled by setting the `throwOnError` option to `false` when |
| 42 | +creating the parser, while collected errors were retrieved using the `getErrors()` method: |
| 43 | + |
| 44 | +```php |
| 45 | +$lexer = ...; |
| 46 | +$parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer, [ |
| 47 | + 'throwOnError' => true, |
| 48 | +]); |
| 49 | + |
| 50 | +$stmts = $parser->parse($code); |
| 51 | +$errors = $parser->getErrors(); |
| 52 | +if ($errors) { |
| 53 | + handleErrors($errors); |
| 54 | +} |
| 55 | +processAst($stmts); |
| 56 | +``` |
| 57 | + |
| 58 | +Both the `throwOnError` option and the `getErrors()` method have been removed in PHP-Parser 3.0. |
| 59 | +Instead an instance of `ErrorHandler\Collecting` should be passed to the `parse()` method: |
| 60 | + |
| 61 | +```php |
| 62 | +$lexer = ...; |
| 63 | +$parser = (new ParserFactory)->create(ParserFactor::ONLY_PHP7, $lexer); |
| 64 | + |
| 65 | +$errorHandler = new ErrorHandler\Collecting; |
| 66 | +$stmts = $parser->parse($code, $errorHandler); |
| 67 | +if ($errorHandler->hasErrors()) { |
| 68 | + handleErrors($errorHandler->getErrors()); |
| 69 | +} |
| 70 | +processAst($stmts); |
| 71 | +``` |
| 72 | + |
| 73 | +#### Multiple parser fallback in error recovery mode |
| 74 | + |
| 75 | +As a result of this change, if a `Multiple` parser is used (e.g. through the `ParserFactory` using |
| 76 | +`PREFER_PHP7` or `PREFER_PHP5`), it will now return the result of the first *non-throwing* parse. As |
| 77 | +parsing never throws in error recovery mode, the result from the first parser will always be |
| 78 | +returned. |
| 79 | + |
| 80 | +The PHP 7 parser is a superset of the PHP 5 parser, with the exceptions that `=& new` and |
| 81 | +`global $$foo->bar` are not supported (other differences are in representation only). The PHP 7 |
| 82 | +parser will be able to recover from the error in both cases. For this reason, this change will |
| 83 | +likely pass unnoticed if you do not specifically test for this syntax. |
| 84 | + |
| 85 | +It is possible to restore the precise previous behavior with the following code: |
| 86 | + |
| 87 | +```php |
| 88 | +$lexer = ...; |
| 89 | +$parser7 = new Parser\Php7($lexer); |
| 90 | +$parser5 = new Parser\Php5($lexer); |
| 91 | + |
| 92 | +$errors7 = new ErrorHandler\Collecting(); |
| 93 | +$stmts7 = $parser7->parse($code, $errors7); |
| 94 | +if ($errors7->hasErrors()) { |
| 95 | + $errors5 = new ErrorHandler\Collecting(); |
| 96 | + $stmts5 = $parser5->parse($code, $errors5); |
| 97 | + if (!$errors5->hasErrors()) { |
| 98 | + // If PHP 7 parse has errors but PHP 5 parse has no errors, use PHP 5 result |
| 99 | + return [$stmts5, $errors5]; |
| 100 | + } |
| 101 | +} |
| 102 | +// If PHP 7 succeeds or both fail use PHP 7 result |
| 103 | +return [$stmts7, $errors7]; |
| 104 | +``` |
| 105 | + |
| 106 | +#### Error handling in the lexer |
| 107 | + |
| 108 | +In order to support recovery from lexer errors, the signature of the `startLexing()` method changed |
| 109 | +to optionally accept an `ErrorHandler`: |
| 110 | + |
| 111 | +```php |
| 112 | +// OLD |
| 113 | +public function startLexing($code); |
| 114 | +// NEW |
| 115 | +public function startLexing($code, ErrorHandler $errorHandler = null); |
| 116 | +``` |
| 117 | + |
| 118 | +If you use a custom lexer with overriden `startLexing()` method, it needs to be changed to accept |
| 119 | +the extra parameter. The value should be passed on to the parent method. |
| 120 | + |
| 121 | +#### Error checks in node constructors |
| 122 | + |
| 123 | +The constructors of certain nodes used to contain additional checks for semantic errors, such as |
| 124 | +creating a try block without either catch or finally. These checks have been moved from the node |
| 125 | +constructors into the parser. This allows recovery from such errors, as well as representing the |
| 126 | +resulting (invalid) AST. |
| 127 | + |
| 128 | +This means that certain error conditions are no longer checked for manually constructed nodes. |
| 129 | + |
| 130 | +### Removed methods, arguments, options |
35 | 131 |
|
36 |
| -The following methods have been removed: |
| 132 | +The following methods, arguments or options have been removed: |
37 | 133 |
|
38 | 134 | * `Comment::setLine()`, `Comment::setText()`: Create new `Comment` instances instead.
|
39 | 135 | * `Name::set()`, `Name::setFirst()`, `Name::setLast()`: Create new `Name` instances instead. For
|
40 | 136 | the latter two a combination of `Name::concat()` and `Name::slice()` can be used.
|
| 137 | + * `Error::getRawLine()`, `Error::setRawLine()`. Use `Error::getStartLine()` and |
| 138 | + `Error::setStartLine()` instead. |
| 139 | + * `Parser::getErrors()`. Use `ErrorHandler\Collecting` instead. |
| 140 | + * `$separator` argument of `Name::toString()`. Use `strtr()` instead, if you really need it. |
| 141 | + * `$cloneNodes` argument of `NodeTraverser::__construct()`. Explicitly clone nodes in the visitor |
| 142 | + instead. |
| 143 | + * `throwOnError` parser option. Use `ErrorHandler\Collecting` instead. |
41 | 144 |
|
42 | 145 | ### Miscellaneous
|
43 | 146 |
|
44 | 147 | * All methods on `PrettyPrinter\Standard` are now protected. Previoulsy most of them were public.
|
45 | 148 | The pretty printer should only be invoked using the `prettyPrint()`, `prettyPrintFile()` and
|
46 | 149 | `prettyPrintExpr()` methods.
|
47 | 150 | * The node dumper now prints numeric values that act as enums/flags in a string representation.
|
48 |
| - If node dumper results are used in tests, updates may be needed to account for this. |
| 151 | + If node dumper results are used in tests, updates may be needed to account for this. |
| 152 | + * The constants on `NameTraverserInterface` have been moved into the `NameTraverser` class. |
| 153 | + * The emulative lexer now directly postprocesses tokens, instead of using `~__EMU__~` sequences. |
| 154 | + This changes the protected API of the emulative lexer. |
0 commit comments