annotate vendor/nikic/php-parser/UPGRADE-3.0.md @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 5fb285c0d0e3
children
rev   line source
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`.