Compare commits

...

23 Commits

Author SHA1 Message Date
21b18eb294 Release version 3.0.0 alpha 1 2016-07-25 15:16:35 +02:00
faa09884db Add upgrading information 2016-07-25 15:09:21 +02:00
b740076ab1 Remove deprecated Name::set*() methods 2016-07-25 14:50:37 +02:00
c9fea2ef67 Extend Name::slice() to support negative length+offset 2016-07-25 14:47:24 +02:00
818ef2e692 Make PrettyPrinter\Standard methods protected
I'm not sure how these ever ended up being public.
2016-07-25 14:27:03 +02:00
5f97b12576 Introduce explicit Finally node 2016-07-25 14:25:04 +02:00
1dea9111a2 NodeDumper: Resolve type for include/use as well 2016-07-25 14:04:04 +02:00
174e6c3cab NodeDumper: Print modifiers as strings 2016-07-25 13:53:49 +02:00
eefcfeed23 Remove analyze.php
Has outlived its usefulness...
2016-07-25 13:38:05 +02:00
18129480ae Rename $type subnode to $flags
Type makes it sound like a type-hint, and on a number of other nodes
$type is used for exactly that. Use $flags to hold modifiers instead.
2016-07-25 13:33:19 +02:00
1b1ff8995b Update some PHP version numbers 2016-07-22 17:07:56 +02:00
867ae5148d Bring Trait constructor in line with Class/interface 2016-07-22 17:01:51 +02:00
72e91845e4 Update changelog 2016-07-22 16:55:17 +02:00
537b59d4d1 PHP 7.1: Support multi-catch
Catch::$type is now an array Catch::$types.
2016-07-22 15:40:00 +02:00
7ff12b8fcb Remove deprecated Comment methods 2016-07-09 22:00:39 +02:00
574665b45b PHP 7.1: list() with keys
Expr\List will now contain ArrayItems instead of plain variables.
I'm reusing ArrayItem, because code handling list() must also handle
arrays, and this allows both to go through the same code path.

This also renames Expr\List->vars to ->items.

TODO: Should Expr\List be dropped in favor of Expr\Array with an
extra flag?
2016-07-09 21:55:55 +02:00
437890d386 PHP 7: Short destructuring syntax
Potentially the pretty printer should force use of [] in assignment
context, instead of relying on the existance of the right attribute.
2016-07-06 23:43:23 +02:00
1edf72c040 PHP 7: Support nullable types
Using a new NullableType node.
2016-07-06 18:36:18 +02:00
7a54aca468 Merge branch '2.x' 2016-07-06 02:21:57 +02:00
5ea2a76d80 PHP 7.1: Class constant visibility support 2016-07-05 23:01:06 +02:00
5044fce1ff PHP 7.1: Add void+iterable support
In PHP 7 mode, these will now be represented as strings 'void'
and 'iterable'.
2016-07-05 22:35:27 +02:00
038e11da4b Remove support for PHP 5.4 2016-07-05 22:29:41 +02:00
225804c147 Targeting PHP-Parser 3.0 2016-07-05 22:24:52 +02:00
69 changed files with 2354 additions and 1590 deletions

View File

@ -7,7 +7,6 @@ cache:
- $HOME/.composer/cache
php:
- 5.4
- 5.5
- 5.6
- 7.0

View File

@ -1,8 +1,61 @@
Version 2.1.1-dev
Version 3.0.0-dev
-----------------
Nothing yet.
Version 3.0.0-alpha1 (2016-07-25)
---------------------------------
### Added
* [7.1] Added support for `void` and `iterable` types. These will now be represented as strings
(instead of `Name` instances) similar to other builtin types.
* [7.1] Added support for class constant visibility. The `ClassConst` node now has a `flags` subnode
holding the visibility modifier, as well as `isPublic()`, `isProtected()` and `isPrivate()`
methods. The constructor changed to accept the additional subnode.
* [7.1] Added support for nullable types. These are represented using a new `NullableType` node
with a single `type` subnode.
* [7.1] Added support for short array destructuring syntax. This means that `Array` nodes may now
appear as the left-hand-side of assignments and foreach value targets. Additionally the array
items may now contain `null` values if elements are skipped.
* [7.1] Added support for keys in list() destructuring. The `List` subnode `vars` has been renamed
to `items` and now contains `ArrayItem`s instead of plain variables.
* [7.1] Added support for multi-catch. The `Catch` subnode `type` has been renamed to `types` and
is now an array of `Name`s.
* `Name::slice()` now supports lengths and negative offsets. This brings it in line with
`array_slice()` functionality.
### Changed
Due to PHP 7.1 support additions described above, the node structure changed as follows:
* `void` and `iterable` types are now stored as strings if the PHP 7 parser is used.
* The `ClassConst` constructor changed to accept an additional `flags` subnode.
* The `Array` subnode `items` may now contain `null` elements (destructuring).
* The `List` subnode `vars` has been renamed to `items` and now contains `ArrayItem`s instead of
plain variables.
* The `Catch` subnode `type` has been renamed to `types` and is now an array of `Name`s.
Additionally the following changes were made:
* The `type` subnode on `Class`, `ClassMethod` and `Property` has been renamed to `flags`. The
`type` subnode has retained for backwards compatibility and is populated to the same value as
`flags`. However, writes to `type` will not update `flags`.
* The `TryCatch` subnode `finallyStmts` has been replaced with a `finally` subnode that holds an
explicit `Finally` node. This allows for more accurate attribute assignment.
* The `Trait` constructor now has the same form as the `Class` and `Interface` constructors: It
takes an array of subnodes. Unlike classes/interfaces, traits can only have a `stmts` subnode.
* The `NodeDumper` now prints class/method/property/constant modifiers, as well as the include and
use type in a textual representation, instead of only showing the number.
* All methods on `PrettyPrinter\Standard` are now protected. Previoulsy most of them were public.
### Removed
* Removed support for running on PHP 5.4. It is however still possible to parse PHP 5.2-5.4 code
while running on a newer version.
* The deprecated `Comment::setLine()` and `Comment::setText()` methods have been removed.
* The deprecated `Name::set()`, `Name::setFirst()` and `Name::setLast()` methods have been removed.
Version 2.1.0 (2016-04-19)
--------------------------
@ -99,7 +152,7 @@ A more detailed description of backwards incompatible changes can be found in th
### Removed
* Removed support for running on PHP 5.4. It is however still possible to parse PHP 5.2 and PHP 5.3
* Removed support for running on PHP 5.3. It is however still possible to parse PHP 5.2 and PHP 5.3
code while running on a newer version.
* Removed legacy class name aliases. This includes the old non-namespaced class names and the old
names for classes that were renamed for PHP 7 compatibility.

View File

@ -3,7 +3,7 @@ PHP Parser
[![Build Status](https://travis-ci.org/nikic/PHP-Parser.svg?branch=master)](https://travis-ci.org/nikic/PHP-Parser) [![Coverage Status](https://coveralls.io/repos/github/nikic/PHP-Parser/badge.svg?branch=master)](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
This is a PHP 5.2 to PHP 7.0 parser written in PHP. Its purpose is to simplify static code analysis and
This is a PHP 5.2 to PHP 7.1 parser written in PHP. Its purpose is to simplify static code analysis and
manipulation.
[**Documentation for version 2.x**][doc_master] (stable; for running on PHP >= 5.4; for parsing PHP 5.2 to PHP 7.0).
@ -93,4 +93,5 @@ Component documentation:
2. [Lexer](doc/component/Lexer.markdown)
[doc_1_x]: https://github.com/nikic/PHP-Parser/tree/1.x/doc
[doc_2_x]: https://github.com/nikic/PHP-Parser/tree/2.x/doc
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc

48
UPGRADE-3.0.md Normal file
View File

@ -0,0 +1,48 @@
Upgrading from PHP-Parser 2.x to 3.0
====================================
This version does not include any major API changes. Only specific details of the node
representation have changed in some cases.
### PHP version requirements
PHP-Parser now requires PHP 5.5 or newer to run. It is however still possible to *parse* PHP 5.2,
5.3 and 5.4 source code, while running on a newer version.
### Changes to the node structure
The following changes are likely to require code changes if the respective nodes are used:
* The `List` subnode `vars` has been renamed to `items` and now contains `ArrayItem`s instead of
plain variables.
* The `Catch` subnode `type` has been renamed to `types` and is now an array of `Name`s.
* The `TryCatch` subnode `finallyStmts` has been replaced with a `finally` subnode that holds an
explicit `Finally` node.
* The `type` subnode on `Class`, `ClassMethod` and `Property` has been renamed to `flags`. The
`type` subnode has retained for backwards compatibility and is populated to the same value as
`flags`. However, writes to `type` will not update `flags` and use of `type` is discouraged.
The following changes are unlikely to require code changes:
* The `ClassConst` constructor changed to accept an additional `flags` subnode.
* The `Trait` constructor now has the same form as the `Class` and `Interface` constructors: It
takes an array of subnodes. Unlike classes/interfaces, traits can only have a `stmts` subnode.
* The `Array` subnode `items` may now contain `null` elements (due to destructuring).
* `void` and `iterable` types are now stored as strings if the PHP 7 parser is used. Previously
these would have been represented as `Name` instances.
### Removed methods
The following methods have been removed:
* `Comment::setLine()`, `Comment::setText()`: Create new `Comment` instances instead.
* `Name::set()`, `Name::setFirst()`, `Name::setLast()`: Create new `Name` instances instead. For
the latter two a combination of `Name::concat()` and `Name::slice()` can be used.
### Miscellaneous
* All methods on `PrettyPrinter\Standard` are now protected. Previoulsy most of them were public.
The pretty printer should only be invoked using the `prettyPrint()`, `prettyPrintFile()` and
`prettyPrintExpr()` methods.
* The node dumper now prints numeric values that act as enums/flags in a string representation.
If node dumper results are used in tests, updates may be needed to account for this.

View File

@ -10,7 +10,7 @@
}
],
"require": {
"php": ">=5.4",
"php": ">=5.5",
"ext-tokenizer": "*"
},
"require-dev": {
@ -24,7 +24,7 @@
"bin": ["bin/php-parse"],
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
"dev-master": "3.0-dev"
}
}
}

View File

@ -1,7 +1,7 @@
Introduction
============
This project is a PHP 5.2 to PHP 7.0 parser **written in PHP itself**.
This project is a PHP 5.2 to PHP 7.1 parser **written in PHP itself**.
What is this for?
-----------------
@ -29,9 +29,9 @@ What can it parse?
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.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.
version it runs on), additionally a wrapper for emulating tokens from newer versions is provided.
This allows to parse PHP 7.1 source code running on PHP 5.5, 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,7 +6,6 @@ What do all those files mean?
* `tokens.y`: Tokens definition shared between PHP 5 and PHP 7 grammars
* `parser.template`: A `kmyacc` parser prototype file for PHP
* `tokens.template`: A `kmyacc` prototype file for the `Tokens` class
* `analyze.php`: Analyzes the grammer and outputs some info about it
* `rebuildParser.php`: Preprocesses the grammar and builds the parser using `kmyacc`
.phpy pseudo language

View File

@ -1,96 +0,0 @@
<?php
const GRAMMAR_FILE = './php5.y';
const LIB = '(?(DEFINE)
(?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\')
(?<doubleQuotedString>"[^\\\\"]*+(?:\\\\.[^\\\\"]*+)*+")
(?<string>(?&singleQuotedString)|(?&doubleQuotedString))
(?<comment>/\*[^*]*+(?:\*(?!/)[^*]*+)*+\*/)
(?<code>\{[^\'"/{}]*+(?:(?:(?&string)|(?&comment)|(?&code)|/)[^\'"/{}]*+)*+})
)';
const RULE_BLOCK = '(?<name>[a-z_]++):(?<rules>[^\'"/{};]*+(?:(?:(?&string)|(?&comment)|(?&code)|/|})[^\'"/{};]*+)*+);';
$usedTerminals = array_flip(array(
'T_VARIABLE', 'T_STRING', 'T_INLINE_HTML', 'T_ENCAPSED_AND_WHITESPACE',
'T_LNUMBER', 'T_DNUMBER', 'T_CONSTANT_ENCAPSED_STRING', 'T_STRING_VARNAME', 'T_NUM_STRING'
));
$unusedNonterminals = array_flip(array(
'case_separator', 'optional_comma'
));
function regex($regex) {
return '~' . LIB . '(?:' . str_replace('~', '\~', $regex) . ')~';
}
function magicSplit($regex, $string) {
$pieces = preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string);
foreach ($pieces as &$piece) {
$piece = trim($piece);
}
return array_filter($pieces);
}
echo '<pre>';
////////////////////
////////////////////
////////////////////
list($defs, $ruleBlocks) = magicSplit('%%', file_get_contents(GRAMMAR_FILE));
if ('' !== trim(preg_replace(regex(RULE_BLOCK), '', $ruleBlocks))) {
die('Not all rule blocks were properly recognized!');
}
preg_match_all(regex(RULE_BLOCK), $ruleBlocks, $ruleBlocksMatches, PREG_SET_ORDER);
foreach ($ruleBlocksMatches as $match) {
$ruleBlockName = $match['name'];
$rules = magicSplit('\|', $match['rules']);
foreach ($rules as &$rule) {
$parts = magicSplit('\s+', $rule);
$usedParts = array();
foreach ($parts as $part) {
if ('{' === $part[0]) {
preg_match_all('~\$([0-9]+)~', $part, $backReferencesMatches, PREG_SET_ORDER);
foreach ($backReferencesMatches as $match) {
$usedParts[$match[1]] = true;
}
}
}
$i = 1;
foreach ($parts as &$part) {
if ('/' === $part[0]) {
continue;
}
if (isset($usedParts[$i])) {
if ('\'' === $part[0] || '{' === $part[0]
|| (ctype_upper($part[0]) && !isset($usedTerminals[$part]))
|| (ctype_lower($part[0]) && isset($unusedNonterminals[$part]))
) {
$part = '<span style="background-color: red; color: white;">' . $part . '</span>';
} else {
$part = '<strong><em>' . $part . '</em></strong>';
}
} elseif ((ctype_upper($part[0]) && isset($usedTerminals[$part]))
|| (ctype_lower($part[0]) && !isset($unusedNonterminals[$part]))
) {
$part = '<span style="background-color: blue; color: white;">' . $part . '</span>';
}
++$i;
}
$rule = implode(' ', $parts);
}
echo $ruleBlockName, ':', "\n", ' ', implode("\n" . ' | ', $rules), "\n", ';', "\n\n";
}

View File

@ -201,12 +201,12 @@ catches:
catch:
T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[$3, parseVar($4), $7]; }
{ $$ = Stmt\Catch_[array($3), parseVar($4), $7]; }
;
optional_finally:
/* empty */ { $$ = null; }
| T_FINALLY '{' inner_statement_list '}' { $$ = $3; }
| T_FINALLY '{' inner_statement_list '}' { $$ = Stmt\Finally_[$3]; }
;
variables_list:
@ -235,7 +235,7 @@ class_declaration_statement:
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
| T_TRAIT T_STRING '{' class_statement_list '}'
{ $$ = Stmt\Trait_[$2, $4]; }
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
;
class_entry_type:
@ -428,7 +428,7 @@ class_statement_list:
class_statement:
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2]; }
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2, 0]; }
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
@ -927,7 +927,7 @@ list_expr_elements:
;
list_expr_element:
variable { $$ = $1; }
variable { $$ = Expr\ArrayItem[$1, null, false]; }
| list_expr { $$ = $1; }
| /* empty */ { $$ = null; }
;

View File

@ -195,14 +195,19 @@ catches:
| catches catch { push($1, $2); }
;
name_union:
name { init($1); }
| name_union '|' name { push($1, $3); }
;
catch:
T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
T_CATCH '(' name_union T_VARIABLE ')' '{' inner_statement_list '}'
{ $$ = Stmt\Catch_[$3, parseVar($4), $7]; }
;
optional_finally:
/* empty */ { $$ = null; }
| T_FINALLY '{' inner_statement_list '}' { $$ = $3; }
| T_FINALLY '{' inner_statement_list '}' { $$ = Stmt\Finally_[$3]; }
;
variables_list:
@ -231,7 +236,7 @@ class_declaration_statement:
| T_INTERFACE T_STRING interface_extends_list '{' class_statement_list '}'
{ $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; }
| T_TRAIT T_STRING '{' class_statement_list '}'
{ $$ = Stmt\Trait_[$2, $4]; }
{ $$ = Stmt\Trait_[$2, ['stmts' => $4]]; }
;
class_entry_type:
@ -344,6 +349,7 @@ foreach_variable:
variable { $$ = array($1, false); }
| '&' variable { $$ = array($2, true); }
| list_expr { $$ = array($1, false); }
| array_short_syntax { $$ = array($1, false); }
;
parameter_list:
@ -363,20 +369,25 @@ parameter:
{ $$ = Node\Param[parseVar($4), $6, $1, $2, $3]; }
;
type_expr:
type { $$ = $1; }
| '?' type { $$ = Node\NullableType[$2]; }
;
type:
name { $$ = $this->handleScalarTypes($1); }
name { $$ = $this->handleBuiltinTypes($1); }
| T_ARRAY { $$ = 'array'; }
| T_CALLABLE { $$ = 'callable'; }
;
optional_param_type:
/* empty */ { $$ = null; }
| type { $$ = $1; }
| type_expr { $$ = $1; }
;
optional_return_type:
/* empty */ { $$ = null; }
| ':' type { $$ = $2; }
| ':' type_expr { $$ = $2; }
;
argument_list:
@ -421,7 +432,7 @@ class_statement_list:
class_statement:
variable_modifiers property_declaration_list ';' { $$ = Stmt\Property[$1, $2]; }
| T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2]; }
| method_modifiers T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$3, $1]; }
| method_modifiers T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type method_body
{ $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; }
| T_USE name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; }
@ -510,6 +521,7 @@ for_expr:
expr:
variable { $$ = $1; }
| list_expr '=' expr { $$ = Expr\Assign[$1, $3]; }
| array_short_syntax '=' expr { $$ = Expr\Assign[$1, $3]; }
| variable '=' expr { $$ = Expr\Assign[$1, $3]; }
| variable '=' '&' variable { $$ = Expr\AssignRef[$1, $4]; }
| variable '=' '&' new_expr { $$ = Expr\AssignRef[$1, $4]; }
@ -675,13 +687,17 @@ constant:
{ $$ = Expr\ClassConstFetch[$1, $3]; }
;
array_short_syntax:
'[' array_pair_list ']'
{ $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT;
$$ = new Expr\Array_($2, $attrs); }
;
dereferencable_scalar:
T_ARRAY '(' array_pair_list ')'
{ $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG;
$$ = new Expr\Array_($3, $attrs); }
| '[' array_pair_list ']'
{ $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT;
$$ = new Expr\Array_($2, $attrs); }
| array_short_syntax { $$ = $1; }
| T_CONSTANT_ENCAPSED_STRING
{ $attrs = attributes(); $attrs['kind'] = strKind($1);
$$ = new Scalar\String_(Scalar\String_::parse($1), $attrs); }
@ -714,11 +730,6 @@ scalar:
parseEncapsedDoc($2, true); $$ = new Scalar\Encapsed($2, $attrs); }
;
optional_comma:
/* empty */
| ','
;
optional_expr:
/* empty */ { $$ = null; }
| expr { $$ = $1; }
@ -794,18 +805,20 @@ list_expr_elements:
;
list_expr_element:
variable { $$ = $1; }
variable { $$ = Expr\ArrayItem[$1, null, false]; }
| list_expr { $$ = $1; }
| expr T_DOUBLE_ARROW variable { $$ = Expr\ArrayItem[$3, $1, false]; }
| expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; }
| /* empty */ { $$ = null; }
;
array_pair_list:
/* empty */ { $$ = array(); }
| non_empty_array_pair_list optional_comma { $$ = $1; }
inner_array_pair_list
{ $$ = $1; $end = count($$)-1; if ($$[$end] === null) unset($$[$end]); }
;
non_empty_array_pair_list:
non_empty_array_pair_list ',' array_pair { push($1, $3); }
inner_array_pair_list:
inner_array_pair_list ',' array_pair { push($1, $3); }
| array_pair { init($1); }
;
@ -814,6 +827,7 @@ array_pair:
| expr { $$ = Expr\ArrayItem[$1, null, false]; }
| expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; }
| '&' variable { $$ = Expr\ArrayItem[$2, null, true]; }
| /* empty */ { $$ = null; }
;
encaps_list:

View File

@ -12,7 +12,7 @@ class Class_ extends Declaration
protected $extends = null;
protected $implements = array();
protected $type = 0;
protected $flags = 0;
protected $uses = array();
protected $constants = array();
@ -112,7 +112,7 @@ class Class_ extends Declaration
*/
public function getNode() {
return new Stmt\Class_($this->name, array(
'type' => $this->type,
'flags' => $this->flags,
'extends' => $this->extends,
'implements' => $this->implements,
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),

View File

@ -9,7 +9,7 @@ use PhpParser\Node\Stmt;
class Method extends FunctionLike
{
protected $name;
protected $type = 0;
protected $flags = 0;
protected $stmts = array();
/**
@ -116,7 +116,7 @@ class Method extends FunctionLike
*/
public function getNode() {
return new Stmt\ClassMethod($this->name, array(
'type' => $this->type,
'flags' => $this->flags,
'byRef' => $this->returnByRef,
'params' => $this->params,
'returnType' => $this->returnType,

View File

@ -9,7 +9,7 @@ class Property extends PhpParser\BuilderAbstract
{
protected $name;
protected $type = 0;
protected $flags = 0;
protected $default = null;
protected $attributes = array();
@ -101,7 +101,7 @@ class Property extends PhpParser\BuilderAbstract
*/
public function getNode() {
return new Stmt\Property(
$this->type !== 0 ? $this->type : Stmt\Class_::MODIFIER_PUBLIC,
$this->flags !== 0 ? $this->flags : Stmt\Class_::MODIFIER_PUBLIC,
array(
new Stmt\PropertyProperty($this->name, $this->default)
),

View File

@ -49,7 +49,9 @@ class Trait_ extends Declaration
*/
public function getNode() {
return new Stmt\Trait_(
$this->name, array_merge($this->properties, $this->methods), $this->attributes
$this->name, array(
'stmts' => array_merge($this->properties, $this->methods)
), $this->attributes
);
}
}

View File

@ -125,7 +125,7 @@ abstract class BuilderAbstract implements Builder {
* @param int $modifier Modifier to set
*/
protected function setModifier($modifier) {
Stmt\Class_::verifyModifier($this->type, $modifier);
$this->type |= $modifier;
Stmt\Class_::verifyModifier($this->flags, $modifier);
$this->flags |= $modifier;
}
}

View File

@ -30,17 +30,6 @@ class Comment
return $this->text;
}
/**
* Sets the comment text.
*
* @param string $text The comment text (including comment delimiters like /*)
*
* @deprecated Construct a new comment instead
*/
public function setText($text) {
$this->text = $text;
}
/**
* Gets the line number the comment started on.
*
@ -50,17 +39,6 @@ class Comment
return $this->line;
}
/**
* Sets the line number the comment started on.
*
* @param int $line Line number
*
* @deprecated Construct a new comment instead
*/
public function setLine($line) {
$this->line = $line;
}
/**
* Gets the file offset the comment started on.
*

View File

@ -21,16 +21,12 @@ class Emulative extends \PhpParser\Lexer
const PHP_7_0 = '7.0.0dev';
const PHP_5_6 = '5.6.0rc1';
const PHP_5_5 = '5.5.0beta1';
public function __construct(array $options = array()) {
parent::__construct($options);
$newKeywordsPerVersion = array(
self::PHP_5_5 => array(
'finally' => Tokens::T_FINALLY,
'yield' => Tokens::T_YIELD,
),
// No new keywords since PHP 5.5
);
$this->newKeywords = array();

View File

@ -6,21 +6,21 @@ use PhpParser\Node\Expr;
class List_ extends Expr
{
/** @var Expr[] List of variables to assign to */
public $vars;
/** @var ArrayItem[] List of items to assign to */
public $items;
/**
* Constructs a list() destructuring node.
*
* @param Expr[] $vars List of variables to assign to
* @param array $attributes Additional attributes
* @param ArrayItem[] $items List of items to assign to
* @param array $attributes Additional attributes
*/
public function __construct(array $vars, array $attributes = array()) {
public function __construct(array $items, array $attributes = array()) {
parent::__construct($attributes);
$this->vars = $vars;
$this->items = $items;
}
public function getSubNodeNames() {
return array('vars');
return array('items');
}
}

View File

@ -103,17 +103,6 @@ class Name extends NodeAbstract
return implode('\\', $this->parts);
}
/**
* Sets the whole name.
*
* @deprecated Create a new Name instead, or manually modify the $parts property
*
* @param string|array|self $name The name to set the whole name to
*/
public function set($name) {
$this->parts = self::prepareName($name);
}
/**
* Prepends a name to this name.
*
@ -136,26 +125,6 @@ class Name extends NodeAbstract
$this->parts = array_merge($this->parts, self::prepareName($name));
}
/**
* Sets the first part of the name.
*
* @deprecated Use concat($first, $name->slice(1)) instead
*
* @param string|array|self $name The name to set the first part to
*/
public function setFirst($name) {
array_splice($this->parts, 0, 1, self::prepareName($name));
}
/**
* Sets the last part of the name.
*
* @param string|array|self $name The name to set the last part to
*/
public function setLast($name) {
array_splice($this->parts, -1, 1, self::prepareName($name));
}
/**
* Gets a slice of a name (similar to array_slice).
*
@ -165,17 +134,31 @@ class Name extends NodeAbstract
* If the slice is empty, a Name with an empty parts array is returned. While this is
* meaningless in itself, it works correctly in conjunction with concat().
*
* @param int $offset Offset to start the slice at
* Offset and length have the same meaning as in array_slice().
*
* @param int $offset Offset to start the slice at (may be negative)
* @param int|null $length Length of the slice (may be negative)
*
* @return static Sliced name
*/
public function slice($offset) {
// TODO negative offset and length
if ($offset < 0 || $offset > count($this->parts)) {
public function slice($offset, $length = null) {
$numParts = count($this->parts);
$realOffset = $offset < 0 ? $offset + $numParts : $offset;
if ($realOffset < 0 || $realOffset > $numParts) {
throw new \OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset));
}
return new static(array_slice($this->parts, $offset), $this->attributes);
if (null === $length) {
$realLength = $numParts - $realOffset;
} else {
$realLength = $length < 0 ? $length + $numParts - $realOffset : $length;
if ($realLength < 0 || $realLength > $numParts) {
throw new \OutOfBoundsException(sprintf('Length %d is out of bounds', $length));
}
}
return new static(array_slice($this->parts, $realOffset, $realLength), $this->attributes);
}
/**

View File

@ -0,0 +1,26 @@
<?php
namespace PhpParser\Node;
use PhpParser\NodeAbstract;
class NullableType extends NodeAbstract
{
/** @var string|Name Type */
public $type;
/**
* Constructs a nullable type (wrapping another type).
*
* @param string|Name $flags Type
* @param array $attributes Additional attributes
*/
public function __construct($flags, array $attributes = array()) {
parent::__construct($attributes);
$this->type = $flags;
}
public function getSubNodeNames() {
return array('type');
}
}

View File

@ -6,8 +6,8 @@ use PhpParser\Node;
class Catch_ extends Node\Stmt
{
/** @var Node\Name Class of exception */
public $type;
/** @var Node\Name[] Types of exceptions to catch */
public $types;
/** @var string Variable for exception */
public $var;
/** @var Node[] Statements */
@ -16,19 +16,19 @@ class Catch_ extends Node\Stmt
/**
* Constructs a catch node.
*
* @param Node\Name $type Class of exception
* @param string $var Variable for exception
* @param Node[] $stmts Statements
* @param array $attributes Additional attributes
* @param Node\Name[] $types Types of exceptions to catch
* @param string $var Variable for exception
* @param Node[] $stmts Statements
* @param array $attributes Additional attributes
*/
public function __construct(Node\Name $type, $var, array $stmts = array(), array $attributes = array()) {
public function __construct(array $types, $var, array $stmts = array(), array $attributes = array()) {
parent::__construct($attributes);
$this->type = $type;
$this->types = $types;
$this->var = $var;
$this->stmts = $stmts;
}
public function getSubNodeNames() {
return array('type', 'var', 'stmts');
return array('types', 'var', 'stmts');
}
}

View File

@ -3,9 +3,12 @@
namespace PhpParser\Node\Stmt;
use PhpParser\Node;
use PhpParser\Error;
class ClassConst extends Node\Stmt
{
/** @var int Modifiers */
public $flags;
/** @var Node\Const_[] Constant declarations */
public $consts;
@ -13,14 +16,43 @@ class ClassConst extends Node\Stmt
* Constructs a class const list node.
*
* @param Node\Const_[] $consts Constant declarations
* @param int $flags Modifiers
* @param array $attributes Additional attributes
*/
public function __construct(array $consts, array $attributes = array()) {
public function __construct(array $consts, $flags = 0, array $attributes = array()) {
if ($flags & Class_::MODIFIER_STATIC) {
throw new Error("Cannot use 'static' as constant modifier");
}
if ($flags & Class_::MODIFIER_ABSTRACT) {
throw new Error("Cannot use 'abstract' as constant modifier");
}
if ($flags & Class_::MODIFIER_FINAL) {
throw new Error("Cannot use 'final' as constant modifier");
}
parent::__construct($attributes);
$this->flags = $flags;
$this->consts = $consts;
}
public function getSubNodeNames() {
return array('consts');
return array('flags', 'consts');
}
public function isPublic() {
return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0
|| ($this->flags & Class_::VISIBILITY_MODIFER_MASK) === 0;
}
public function isProtected() {
return (bool) ($this->flags & Class_::MODIFIER_PROTECTED);
}
public function isPrivate() {
return (bool) ($this->flags & Class_::MODIFIER_PRIVATE);
}
public function isStatic() {
return (bool) ($this->flags & Class_::MODIFIER_STATIC);
}
}

View File

@ -8,8 +8,8 @@ use PhpParser\Error;
class ClassMethod extends Node\Stmt implements FunctionLike
{
/** @var int Type */
public $type;
/** @var int Flags */
public $flags;
/** @var bool Whether to return by reference */
public $byRef;
/** @var string Name */
@ -21,12 +21,15 @@ class ClassMethod extends Node\Stmt implements FunctionLike
/** @var Node[] Statements */
public $stmts;
/** @deprecated Use $flags instead */
public $type;
/**
* Constructs a class method node.
*
* @param string $name Name
* @param array $subNodes Array of the following optional subnodes:
* 'type' => MODIFIER_PUBLIC: Type
* 'flags => MODIFIER_PUBLIC: Flags
* 'byRef' => false : Whether to return by reference
* 'params' => array() : Parameters
* 'returnType' => null : Return type
@ -35,14 +38,16 @@ class ClassMethod extends Node\Stmt implements FunctionLike
*/
public function __construct($name, array $subNodes = array(), array $attributes = array()) {
parent::__construct($attributes);
$this->type = isset($subNodes['type']) ? $subNodes['type'] : 0;
$this->flags = isset($subNodes['flags']) ? $subNodes['flags']
: (isset($subNodes['type']) ? $subNodes['type'] : 0);
$this->type = $this->flags;
$this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : false;
$this->name = $name;
$this->params = isset($subNodes['params']) ? $subNodes['params'] : array();
$this->returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null;
$this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : array();
if ($this->type & Class_::MODIFIER_STATIC) {
if ($this->flags & Class_::MODIFIER_STATIC) {
switch (strtolower($this->name)) {
case '__construct':
throw new Error(sprintf('Constructor %s() cannot be static', $this->name));
@ -55,7 +60,7 @@ class ClassMethod extends Node\Stmt implements FunctionLike
}
public function getSubNodeNames() {
return array('type', 'byRef', 'name', 'params', 'returnType', 'stmts');
return array('flags', 'byRef', 'name', 'params', 'returnType', 'stmts');
}
public function returnsByRef() {
@ -75,27 +80,27 @@ class ClassMethod extends Node\Stmt implements FunctionLike
}
public function isPublic() {
return ($this->type & Class_::MODIFIER_PUBLIC) !== 0
|| ($this->type & Class_::VISIBILITY_MODIFER_MASK) === 0;
return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0
|| ($this->flags & Class_::VISIBILITY_MODIFER_MASK) === 0;
}
public function isProtected() {
return (bool) ($this->type & Class_::MODIFIER_PROTECTED);
return (bool) ($this->flags & Class_::MODIFIER_PROTECTED);
}
public function isPrivate() {
return (bool) ($this->type & Class_::MODIFIER_PRIVATE);
return (bool) ($this->flags & Class_::MODIFIER_PRIVATE);
}
public function isAbstract() {
return (bool) ($this->type & Class_::MODIFIER_ABSTRACT);
return (bool) ($this->flags & Class_::MODIFIER_ABSTRACT);
}
public function isFinal() {
return (bool) ($this->type & Class_::MODIFIER_FINAL);
return (bool) ($this->flags & Class_::MODIFIER_FINAL);
}
public function isStatic() {
return (bool) ($this->type & Class_::MODIFIER_STATIC);
return (bool) ($this->flags & Class_::MODIFIER_STATIC);
}
}

View File

@ -17,12 +17,15 @@ class Class_ extends ClassLike
const VISIBILITY_MODIFER_MASK = 7; // 1 | 2 | 4
/** @var int Type */
public $type;
public $flags;
/** @var null|Node\Name Name of extended class */
public $extends;
/** @var Node\Name[] Names of implemented interfaces */
public $implements;
/** @deprecated Use $flags instead */
public $type;
protected static $specialNames = array(
'self' => true,
'parent' => true,
@ -34,7 +37,7 @@ class Class_ extends ClassLike
*
* @param string|null $name Name
* @param array $subNodes Array of the following optional subnodes:
* 'type' => 0 : Type
* 'flags' => 0 : Flags
* 'extends' => null : Name of extended class
* 'implements' => array(): Names of implemented interfaces
* 'stmts' => array(): Statements
@ -42,7 +45,9 @@ class Class_ extends ClassLike
*/
public function __construct($name, array $subNodes = array(), array $attributes = array()) {
parent::__construct($attributes);
$this->type = isset($subNodes['type']) ? $subNodes['type'] : 0;
$this->flags = isset($subNodes['flags']) ? $subNodes['flags']
: (isset($subNodes['type']) ? $subNodes['type'] : 0);
$this->type = $this->flags;
$this->name = $name;
$this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : null;
$this->implements = isset($subNodes['implements']) ? $subNodes['implements'] : array();
@ -70,15 +75,15 @@ class Class_ extends ClassLike
}
public function getSubNodeNames() {
return array('type', 'name', 'extends', 'implements', 'stmts');
return array('flags', 'name', 'extends', 'implements', 'stmts');
}
public function isAbstract() {
return (bool) ($this->type & self::MODIFIER_ABSTRACT);
return (bool) ($this->flags & self::MODIFIER_ABSTRACT);
}
public function isFinal() {
return (bool) ($this->type & self::MODIFIER_FINAL);
return (bool) ($this->flags & self::MODIFIER_FINAL);
}
public function isAnonymous() {

View File

@ -0,0 +1,26 @@
<?php
namespace PhpParser\Node\Stmt;
use PhpParser\Node;
class Finally_ extends Node\Stmt
{
/** @var Node[] Statements */
public $stmts;
/**
* Constructs a finally node.
*
* @param Node[] $stmts Statements
* @param array $attributes Additional attributes
*/
public function __construct(array $stmts = array(), array $attributes = array()) {
parent::__construct($attributes);
$this->stmts = $stmts;
}
public function getSubNodeNames() {
return array('stmts');
}
}

View File

@ -8,49 +8,53 @@ use PhpParser\Error;
class Property extends Node\Stmt
{
/** @var int Modifiers */
public $type;
public $flags;
/** @var PropertyProperty[] Properties */
public $props;
/** @deprecated Use $flags instead */
public $type;
/**
* Constructs a class property list node.
*
* @param int $type Modifiers
* @param int $flags Modifiers
* @param PropertyProperty[] $props Properties
* @param array $attributes Additional attributes
*/
public function __construct($type, array $props, array $attributes = array()) {
if ($type & Class_::MODIFIER_ABSTRACT) {
public function __construct($flags, array $props, array $attributes = array()) {
if ($flags & Class_::MODIFIER_ABSTRACT) {
throw new Error('Properties cannot be declared abstract');
}
if ($type & Class_::MODIFIER_FINAL) {
if ($flags & Class_::MODIFIER_FINAL) {
throw new Error('Properties cannot be declared final');
}
parent::__construct($attributes);
$this->type = $type;
$this->flags = $flags;
$this->type = $flags;
$this->props = $props;
}
public function getSubNodeNames() {
return array('type', 'props');
return array('flags', 'props');
}
public function isPublic() {
return ($this->type & Class_::MODIFIER_PUBLIC) !== 0
|| ($this->type & Class_::VISIBILITY_MODIFER_MASK) === 0;
return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0
|| ($this->flags & Class_::VISIBILITY_MODIFER_MASK) === 0;
}
public function isProtected() {
return (bool) ($this->type & Class_::MODIFIER_PROTECTED);
return (bool) ($this->flags & Class_::MODIFIER_PROTECTED);
}
public function isPrivate() {
return (bool) ($this->type & Class_::MODIFIER_PRIVATE);
return (bool) ($this->flags & Class_::MODIFIER_PRIVATE);
}
public function isStatic() {
return (bool) ($this->type & Class_::MODIFIER_STATIC);
return (bool) ($this->flags & Class_::MODIFIER_STATIC);
}
}

View File

@ -10,13 +10,14 @@ class Trait_ extends ClassLike
* Constructs a trait node.
*
* @param string $name Name
* @param Node[] $stmts Statements
* @param array $subNodes Array of the following optional subnodes:
* 'stmts' => array(): Statements
* @param array $attributes Additional attributes
*/
public function __construct($name, array $stmts = array(), array $attributes = array()) {
public function __construct($name, array $subNodes = array(), array $attributes = array()) {
parent::__construct($attributes);
$this->name = $name;
$this->stmts = $stmts;
$this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : array();
}
public function getSubNodeNames() {

View File

@ -11,29 +11,29 @@ class TryCatch extends Node\Stmt
public $stmts;
/** @var Catch_[] Catches */
public $catches;
/** @var null|Node[] Finally statements */
public $finallyStmts;
/** @var null|Finally_ Optional finally node */
public $finally;
/**
* Constructs a try catch node.
*
* @param Node[] $stmts Statements
* @param Catch_[] $catches Catches
* @param null|Node[] $finallyStmts Finally statements (null means no finally clause)
* @param array|null $attributes Additional attributes
* @param Node[] $stmts Statements
* @param Catch_[] $catches Catches
* @param null|Finally_ $finally Optionaly finally node
* @param array|null $attributes Additional attributes
*/
public function __construct(array $stmts, array $catches, array $finallyStmts = null, array $attributes = array()) {
if (empty($catches) && null === $finallyStmts) {
public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = array()) {
if (empty($catches) && null === $finally) {
throw new Error('Cannot use try without catch or finally');
}
parent::__construct($attributes);
$this->stmts = $stmts;
$this->catches = $catches;
$this->finallyStmts = $finallyStmts;
$this->finally = $finally;
}
public function getSubNodeNames() {
return array('stmts', 'catches', 'finallyStmts');
return array('stmts', 'catches', 'finally');
}
}

View File

@ -2,6 +2,12 @@
namespace PhpParser;
use PhpParser\Node\Expr\Include_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
class NodeDumper
{
private $dumpComments;
@ -38,7 +44,16 @@ class NodeDumper
} elseif (true === $value) {
$r .= 'true';
} elseif (is_scalar($value)) {
$r .= $value;
if ('flags' === $key || 'newModifier' === $key) {
$r .= $this->dumpFlags($value);
} else if ('type' === $key && $node instanceof Include_) {
$r .= $this->dumpIncludeType($value);
} else if ('type' === $key
&& ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) {
$r .= $this->dumpUseType($value);
} else {
$r .= $value;
}
} else {
$r .= str_replace("\n", "\n ", $this->dump($value));
}
@ -73,4 +88,60 @@ class NodeDumper
return $r . "\n)";
}
protected function dumpFlags($flags) {
$strs = [];
if ($flags & Class_::MODIFIER_PUBLIC) {
$strs[] = 'MODIFIER_PUBLIC';
}
if ($flags & Class_::MODIFIER_PROTECTED) {
$strs[] = 'MODIFIER_PROTECTED';
}
if ($flags & Class_::MODIFIER_PRIVATE) {
$strs[] = 'MODIFIER_PRIVATE';
}
if ($flags & Class_::MODIFIER_ABSTRACT) {
$strs[] = 'MODIFIER_ABSTRACT';
}
if ($flags & Class_::MODIFIER_STATIC) {
$strs[] = 'MODIFIER_STATIC';
}
if ($flags & Class_::MODIFIER_FINAL) {
$strs[] = 'MODIFIER_FINAL';
}
if ($strs) {
return implode(' | ', $strs) . ' (' . $flags . ')';
} else {
return $flags;
}
}
protected function dumpIncludeType($type) {
$map = [
Include_::TYPE_INCLUDE => 'TYPE_INCLUDE',
Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',
Include_::TYPE_REQUIRE => 'TYPE_REQUIRE',
Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQURE_ONCE',
];
if (!isset($map[$type])) {
return $type;
}
return $map[$type] . ' (' . $type . ')';
}
protected function dumpUseType($type) {
$map = [
Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN',
Use_::TYPE_NORMAL => 'TYPE_NORMAL',
Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',
Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',
];
if (!isset($map[$type])) {
return $type;
}
return $map[$type] . ' (' . $type . ')';
}
}

View File

@ -74,7 +74,9 @@ class NameResolver extends NodeVisitorAbstract
$node->class = $this->resolveClassName($node->class);
}
} elseif ($node instanceof Stmt\Catch_) {
$node->type = $this->resolveClassName($node->type);
foreach ($node->types as &$type) {
$type = $this->resolveClassName($type);
}
} elseif ($node instanceof Expr\FuncCall) {
if ($node->name instanceof Name) {
$node->name = $this->resolveOtherName($node->name, Stmt\Use_::TYPE_FUNCTION);

View File

@ -1553,7 +1553,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule160() {
$this->semValue = new Stmt\Catch_($this->semStack[$this->stackPos-(8-3)], substr($this->semStack[$this->stackPos-(8-4)], 1), $this->semStack[$this->stackPos-(8-7)], $this->startAttributeStack[$this->stackPos-(8-1)] + $this->endAttributes);
$this->semValue = new Stmt\Catch_(array($this->semStack[$this->stackPos-(8-3)]), substr($this->semStack[$this->stackPos-(8-4)], 1), $this->semStack[$this->stackPos-(8-7)], $this->startAttributeStack[$this->stackPos-(8-1)] + $this->endAttributes);
}
protected function reduceRule161() {
@ -1561,7 +1561,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule162() {
$this->semValue = $this->semStack[$this->stackPos-(4-3)];
$this->semValue = new Stmt\Finally_($this->semStack[$this->stackPos-(4-3)], $this->startAttributeStack[$this->stackPos-(4-1)] + $this->endAttributes);
}
protected function reduceRule163() {
@ -1601,7 +1601,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule172() {
$this->semValue = new Stmt\Trait_($this->semStack[$this->stackPos-(5-2)], $this->semStack[$this->stackPos-(5-4)], $this->startAttributeStack[$this->stackPos-(5-1)] + $this->endAttributes);
$this->semValue = new Stmt\Trait_($this->semStack[$this->stackPos-(5-2)], ['stmts' => $this->semStack[$this->stackPos-(5-4)]], $this->startAttributeStack[$this->stackPos-(5-1)] + $this->endAttributes);
}
protected function reduceRule173() {
@ -1921,7 +1921,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule252() {
$this->semValue = new Stmt\ClassConst($this->semStack[$this->stackPos-(3-2)], $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
$this->semValue = new Stmt\ClassConst($this->semStack[$this->stackPos-(3-2)], 0, $this->startAttributeStack[$this->stackPos-(3-1)] + $this->endAttributes);
}
protected function reduceRule253() {
@ -3021,7 +3021,7 @@ class Php5 extends \PhpParser\ParserAbstract
}
protected function reduceRule521() {
$this->semValue = $this->semStack[$this->stackPos-(1-1)];
$this->semValue = new Expr\ArrayItem($this->semStack[$this->stackPos-(1-1)], null, false, $this->startAttributeStack[$this->stackPos-(1-1)] + $this->endAttributes);
}
protected function reduceRule522() {

File diff suppressed because it is too large Load Diff

View File

@ -483,12 +483,14 @@ abstract class ParserAbstract implements Parser
return $style;
}
protected function handleScalarTypes(Name $name) {
protected function handleBuiltinTypes(Name $name) {
$scalarTypes = [
'bool' => true,
'int' => true,
'float' => true,
'string' => true,
'bool' => true,
'int' => true,
'float' => true,
'string' => true,
'iterable' => true,
'void' => true,
];
if (!$name->isUnqualified()) {

View File

@ -17,7 +17,7 @@ class Standard extends PrettyPrinterAbstract
{
// Special nodes
public function pParam(Node\Param $node) {
protected function pParam(Node\Param $node) {
return ($node->type ? $this->pType($node->type) . ' ' : '')
. ($node->byRef ? '&' : '')
. ($node->variadic ? '...' : '')
@ -25,65 +25,69 @@ class Standard extends PrettyPrinterAbstract
. ($node->default ? ' = ' . $this->p($node->default) : '');
}
public function pArg(Node\Arg $node) {
protected function pArg(Node\Arg $node) {
return ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value);
}
public function pConst(Node\Const_ $node) {
protected function pConst(Node\Const_ $node) {
return $node->name . ' = ' . $this->p($node->value);
}
protected function pNullableType(Node\NullableType $node) {
return '?' . $node->type;
}
// Names
public function pName(Name $node) {
protected function pName(Name $node) {
return implode('\\', $node->parts);
}
public function pName_FullyQualified(Name\FullyQualified $node) {
protected function pName_FullyQualified(Name\FullyQualified $node) {
return '\\' . implode('\\', $node->parts);
}
public function pName_Relative(Name\Relative $node) {
protected function pName_Relative(Name\Relative $node) {
return 'namespace\\' . implode('\\', $node->parts);
}
// Magic Constants
public function pScalar_MagicConst_Class(MagicConst\Class_ $node) {
protected function pScalar_MagicConst_Class(MagicConst\Class_ $node) {
return '__CLASS__';
}
public function pScalar_MagicConst_Dir(MagicConst\Dir $node) {
protected function pScalar_MagicConst_Dir(MagicConst\Dir $node) {
return '__DIR__';
}
public function pScalar_MagicConst_File(MagicConst\File $node) {
protected function pScalar_MagicConst_File(MagicConst\File $node) {
return '__FILE__';
}
public function pScalar_MagicConst_Function(MagicConst\Function_ $node) {
protected function pScalar_MagicConst_Function(MagicConst\Function_ $node) {
return '__FUNCTION__';
}
public function pScalar_MagicConst_Line(MagicConst\Line $node) {
protected function pScalar_MagicConst_Line(MagicConst\Line $node) {
return '__LINE__';
}
public function pScalar_MagicConst_Method(MagicConst\Method $node) {
protected function pScalar_MagicConst_Method(MagicConst\Method $node) {
return '__METHOD__';
}
public function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) {
protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) {
return '__NAMESPACE__';
}
public function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) {
protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) {
return '__TRAIT__';
}
// Scalars
public function pScalar_String(Scalar\String_ $node) {
protected function pScalar_String(Scalar\String_ $node) {
$kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED);
switch ($kind) {
case Scalar\String_::KIND_NOWDOC:
@ -117,7 +121,7 @@ class Standard extends PrettyPrinterAbstract
throw new \Exception('Invalid string kind');
}
public function pScalar_Encapsed(Scalar\Encapsed $node) {
protected function pScalar_Encapsed(Scalar\Encapsed $node) {
if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) {
$label = $node->getAttribute('docLabel');
if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) {
@ -136,7 +140,7 @@ class Standard extends PrettyPrinterAbstract
return '"' . $this->pEncapsList($node->parts, '"') . '"';
}
public function pScalar_LNumber(Scalar\LNumber $node) {
protected function pScalar_LNumber(Scalar\LNumber $node) {
$str = (string) $node->value;
switch ($node->getAttribute('kind', Scalar\LNumber::KIND_DEC)) {
case Scalar\LNumber::KIND_BIN:
@ -151,7 +155,7 @@ class Standard extends PrettyPrinterAbstract
throw new \Exception('Invalid number kind');
}
public function pScalar_DNumber(Scalar\DNumber $node) {
protected function pScalar_DNumber(Scalar\DNumber $node) {
$stringValue = sprintf('%.16G', $node->value);
if ($node->value !== (double) $stringValue) {
$stringValue = sprintf('%.17G', $node->value);
@ -163,265 +167,265 @@ class Standard extends PrettyPrinterAbstract
// Assignments
public function pExpr_Assign(Expr\Assign $node) {
protected function pExpr_Assign(Expr\Assign $node) {
return $this->pInfixOp('Expr_Assign', $node->var, ' = ', $node->expr);
}
public function pExpr_AssignRef(Expr\AssignRef $node) {
protected function pExpr_AssignRef(Expr\AssignRef $node) {
return $this->pInfixOp('Expr_AssignRef', $node->var, ' =& ', $node->expr);
}
public function pExpr_AssignOp_Plus(AssignOp\Plus $node) {
protected function pExpr_AssignOp_Plus(AssignOp\Plus $node) {
return $this->pInfixOp('Expr_AssignOp_Plus', $node->var, ' += ', $node->expr);
}
public function pExpr_AssignOp_Minus(AssignOp\Minus $node) {
protected function pExpr_AssignOp_Minus(AssignOp\Minus $node) {
return $this->pInfixOp('Expr_AssignOp_Minus', $node->var, ' -= ', $node->expr);
}
public function pExpr_AssignOp_Mul(AssignOp\Mul $node) {
protected function pExpr_AssignOp_Mul(AssignOp\Mul $node) {
return $this->pInfixOp('Expr_AssignOp_Mul', $node->var, ' *= ', $node->expr);
}
public function pExpr_AssignOp_Div(AssignOp\Div $node) {
protected function pExpr_AssignOp_Div(AssignOp\Div $node) {
return $this->pInfixOp('Expr_AssignOp_Div', $node->var, ' /= ', $node->expr);
}
public function pExpr_AssignOp_Concat(AssignOp\Concat $node) {
protected function pExpr_AssignOp_Concat(AssignOp\Concat $node) {
return $this->pInfixOp('Expr_AssignOp_Concat', $node->var, ' .= ', $node->expr);
}
public function pExpr_AssignOp_Mod(AssignOp\Mod $node) {
protected function pExpr_AssignOp_Mod(AssignOp\Mod $node) {
return $this->pInfixOp('Expr_AssignOp_Mod', $node->var, ' %= ', $node->expr);
}
public function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) {
protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) {
return $this->pInfixOp('Expr_AssignOp_BitwiseAnd', $node->var, ' &= ', $node->expr);
}
public function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) {
protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) {
return $this->pInfixOp('Expr_AssignOp_BitwiseOr', $node->var, ' |= ', $node->expr);
}
public function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) {
protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) {
return $this->pInfixOp('Expr_AssignOp_BitwiseXor', $node->var, ' ^= ', $node->expr);
}
public function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) {
protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) {
return $this->pInfixOp('Expr_AssignOp_ShiftLeft', $node->var, ' <<= ', $node->expr);
}
public function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) {
protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) {
return $this->pInfixOp('Expr_AssignOp_ShiftRight', $node->var, ' >>= ', $node->expr);
}
public function pExpr_AssignOp_Pow(AssignOp\Pow $node) {
protected function pExpr_AssignOp_Pow(AssignOp\Pow $node) {
return $this->pInfixOp('Expr_AssignOp_Pow', $node->var, ' **= ', $node->expr);
}
// Binary expressions
public function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) {
protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) {
return $this->pInfixOp('Expr_BinaryOp_Plus', $node->left, ' + ', $node->right);
}
public function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) {
protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) {
return $this->pInfixOp('Expr_BinaryOp_Minus', $node->left, ' - ', $node->right);
}
public function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) {
protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) {
return $this->pInfixOp('Expr_BinaryOp_Mul', $node->left, ' * ', $node->right);
}
public function pExpr_BinaryOp_Div(BinaryOp\Div $node) {
protected function pExpr_BinaryOp_Div(BinaryOp\Div $node) {
return $this->pInfixOp('Expr_BinaryOp_Div', $node->left, ' / ', $node->right);
}
public function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) {
protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) {
return $this->pInfixOp('Expr_BinaryOp_Concat', $node->left, ' . ', $node->right);
}
public function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) {
protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) {
return $this->pInfixOp('Expr_BinaryOp_Mod', $node->left, ' % ', $node->right);
}
public function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) {
protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) {
return $this->pInfixOp('Expr_BinaryOp_BooleanAnd', $node->left, ' && ', $node->right);
}
public function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) {
protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) {
return $this->pInfixOp('Expr_BinaryOp_BooleanOr', $node->left, ' || ', $node->right);
}
public function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) {
protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) {
return $this->pInfixOp('Expr_BinaryOp_BitwiseAnd', $node->left, ' & ', $node->right);
}
public function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) {
protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) {
return $this->pInfixOp('Expr_BinaryOp_BitwiseOr', $node->left, ' | ', $node->right);
}
public function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) {
protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) {
return $this->pInfixOp('Expr_BinaryOp_BitwiseXor', $node->left, ' ^ ', $node->right);
}
public function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) {
protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) {
return $this->pInfixOp('Expr_BinaryOp_ShiftLeft', $node->left, ' << ', $node->right);
}
public function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) {
protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) {
return $this->pInfixOp('Expr_BinaryOp_ShiftRight', $node->left, ' >> ', $node->right);
}
public function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) {
protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) {
return $this->pInfixOp('Expr_BinaryOp_Pow', $node->left, ' ** ', $node->right);
}
public function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) {
protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) {
return $this->pInfixOp('Expr_BinaryOp_LogicalAnd', $node->left, ' and ', $node->right);
}
public function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) {
protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) {
return $this->pInfixOp('Expr_BinaryOp_LogicalOr', $node->left, ' or ', $node->right);
}
public function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) {
protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) {
return $this->pInfixOp('Expr_BinaryOp_LogicalXor', $node->left, ' xor ', $node->right);
}
public function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) {
protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) {
return $this->pInfixOp('Expr_BinaryOp_Equal', $node->left, ' == ', $node->right);
}
public function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) {
protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) {
return $this->pInfixOp('Expr_BinaryOp_NotEqual', $node->left, ' != ', $node->right);
}
public function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) {
protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) {
return $this->pInfixOp('Expr_BinaryOp_Identical', $node->left, ' === ', $node->right);
}
public function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) {
protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) {
return $this->pInfixOp('Expr_BinaryOp_NotIdentical', $node->left, ' !== ', $node->right);
}
public function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) {
protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) {
return $this->pInfixOp('Expr_BinaryOp_Spaceship', $node->left, ' <=> ', $node->right);
}
public function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) {
protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) {
return $this->pInfixOp('Expr_BinaryOp_Greater', $node->left, ' > ', $node->right);
}
public function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) {
protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) {
return $this->pInfixOp('Expr_BinaryOp_GreaterOrEqual', $node->left, ' >= ', $node->right);
}
public function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) {
protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) {
return $this->pInfixOp('Expr_BinaryOp_Smaller', $node->left, ' < ', $node->right);
}
public function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) {
protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) {
return $this->pInfixOp('Expr_BinaryOp_SmallerOrEqual', $node->left, ' <= ', $node->right);
}
public function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) {
protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) {
return $this->pInfixOp('Expr_BinaryOp_Coalesce', $node->left, ' ?? ', $node->right);
}
public function pExpr_Instanceof(Expr\Instanceof_ $node) {
protected function pExpr_Instanceof(Expr\Instanceof_ $node) {
return $this->pInfixOp('Expr_Instanceof', $node->expr, ' instanceof ', $node->class);
}
// Unary expressions
public function pExpr_BooleanNot(Expr\BooleanNot $node) {
protected function pExpr_BooleanNot(Expr\BooleanNot $node) {
return $this->pPrefixOp('Expr_BooleanNot', '!', $node->expr);
}
public function pExpr_BitwiseNot(Expr\BitwiseNot $node) {
protected function pExpr_BitwiseNot(Expr\BitwiseNot $node) {
return $this->pPrefixOp('Expr_BitwiseNot', '~', $node->expr);
}
public function pExpr_UnaryMinus(Expr\UnaryMinus $node) {
protected function pExpr_UnaryMinus(Expr\UnaryMinus $node) {
return $this->pPrefixOp('Expr_UnaryMinus', '-', $node->expr);
}
public function pExpr_UnaryPlus(Expr\UnaryPlus $node) {
protected function pExpr_UnaryPlus(Expr\UnaryPlus $node) {
return $this->pPrefixOp('Expr_UnaryPlus', '+', $node->expr);
}
public function pExpr_PreInc(Expr\PreInc $node) {
protected function pExpr_PreInc(Expr\PreInc $node) {
return $this->pPrefixOp('Expr_PreInc', '++', $node->var);
}
public function pExpr_PreDec(Expr\PreDec $node) {
protected function pExpr_PreDec(Expr\PreDec $node) {
return $this->pPrefixOp('Expr_PreDec', '--', $node->var);
}
public function pExpr_PostInc(Expr\PostInc $node) {
protected function pExpr_PostInc(Expr\PostInc $node) {
return $this->pPostfixOp('Expr_PostInc', $node->var, '++');
}
public function pExpr_PostDec(Expr\PostDec $node) {
protected function pExpr_PostDec(Expr\PostDec $node) {
return $this->pPostfixOp('Expr_PostDec', $node->var, '--');
}
public function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) {
protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) {
return $this->pPrefixOp('Expr_ErrorSuppress', '@', $node->expr);
}
public function pExpr_YieldFrom(Expr\YieldFrom $node) {
protected function pExpr_YieldFrom(Expr\YieldFrom $node) {
return $this->pPrefixOp('Expr_YieldFrom', 'yield from ', $node->expr);
}
public function pExpr_Print(Expr\Print_ $node) {
protected function pExpr_Print(Expr\Print_ $node) {
return $this->pPrefixOp('Expr_Print', 'print ', $node->expr);
}
// Casts
public function pExpr_Cast_Int(Cast\Int_ $node) {
protected function pExpr_Cast_Int(Cast\Int_ $node) {
return $this->pPrefixOp('Expr_Cast_Int', '(int) ', $node->expr);
}
public function pExpr_Cast_Double(Cast\Double $node) {
protected function pExpr_Cast_Double(Cast\Double $node) {
return $this->pPrefixOp('Expr_Cast_Double', '(double) ', $node->expr);
}
public function pExpr_Cast_String(Cast\String_ $node) {
protected function pExpr_Cast_String(Cast\String_ $node) {
return $this->pPrefixOp('Expr_Cast_String', '(string) ', $node->expr);
}
public function pExpr_Cast_Array(Cast\Array_ $node) {
protected function pExpr_Cast_Array(Cast\Array_ $node) {
return $this->pPrefixOp('Expr_Cast_Array', '(array) ', $node->expr);
}
public function pExpr_Cast_Object(Cast\Object_ $node) {
protected function pExpr_Cast_Object(Cast\Object_ $node) {
return $this->pPrefixOp('Expr_Cast_Object', '(object) ', $node->expr);
}
public function pExpr_Cast_Bool(Cast\Bool_ $node) {
protected function pExpr_Cast_Bool(Cast\Bool_ $node) {
return $this->pPrefixOp('Expr_Cast_Bool', '(bool) ', $node->expr);
}
public function pExpr_Cast_Unset(Cast\Unset_ $node) {
protected function pExpr_Cast_Unset(Cast\Unset_ $node) {
return $this->pPrefixOp('Expr_Cast_Unset', '(unset) ', $node->expr);
}
// Function calls and similar constructs
public function pExpr_FuncCall(Expr\FuncCall $node) {
protected function pExpr_FuncCall(Expr\FuncCall $node) {
return $this->pCallLhs($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_MethodCall(Expr\MethodCall $node) {
protected function pExpr_MethodCall(Expr\MethodCall $node) {
return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name)
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_StaticCall(Expr\StaticCall $node) {
protected function pExpr_StaticCall(Expr\StaticCall $node) {
return $this->pDereferenceLhs($node->class) . '::'
. ($node->name instanceof Expr
? ($node->name instanceof Expr\Variable
@ -431,19 +435,19 @@ class Standard extends PrettyPrinterAbstract
. '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Empty(Expr\Empty_ $node) {
protected function pExpr_Empty(Expr\Empty_ $node) {
return 'empty(' . $this->p($node->expr) . ')';
}
public function pExpr_Isset(Expr\Isset_ $node) {
protected function pExpr_Isset(Expr\Isset_ $node) {
return 'isset(' . $this->pCommaSeparated($node->vars) . ')';
}
public function pExpr_Eval(Expr\Eval_ $node) {
protected function pExpr_Eval(Expr\Eval_ $node) {
return 'eval(' . $this->p($node->expr) . ')';
}
public function pExpr_Include(Expr\Include_ $node) {
protected function pExpr_Include(Expr\Include_ $node) {
static $map = array(
Expr\Include_::TYPE_INCLUDE => 'include',
Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once',
@ -454,22 +458,13 @@ class Standard extends PrettyPrinterAbstract
return $map[$node->type] . ' ' . $this->p($node->expr);
}
public function pExpr_List(Expr\List_ $node) {
$pList = array();
foreach ($node->vars as $var) {
if (null === $var) {
$pList[] = '';
} else {
$pList[] = $this->p($var);
}
}
return 'list(' . implode(', ', $pList) . ')';
protected function pExpr_List(Expr\List_ $node) {
return 'list(' . $this->pCommaSeparated($node->items) . ')';
}
// Other
public function pExpr_Variable(Expr\Variable $node) {
protected function pExpr_Variable(Expr\Variable $node) {
if ($node->name instanceof Expr) {
return '${' . $this->p($node->name) . '}';
} else {
@ -477,7 +472,7 @@ class Standard extends PrettyPrinterAbstract
}
}
public function pExpr_Array(Expr\Array_ $node) {
protected function pExpr_Array(Expr\Array_ $node) {
$syntax = $node->getAttribute('kind',
$this->options['shortArraySyntax'] ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG);
if ($syntax === Expr\Array_::KIND_SHORT) {
@ -487,37 +482,37 @@ class Standard extends PrettyPrinterAbstract
}
}
public function pExpr_ArrayItem(Expr\ArrayItem $node) {
protected function pExpr_ArrayItem(Expr\ArrayItem $node) {
return (null !== $node->key ? $this->p($node->key) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->value);
}
public function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) {
protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) {
return $this->pDereferenceLhs($node->var)
. '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';
}
public function pExpr_ConstFetch(Expr\ConstFetch $node) {
protected function pExpr_ConstFetch(Expr\ConstFetch $node) {
return $this->p($node->name);
}
public function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) {
return $this->p($node->class) . '::' . $node->name;
}
public function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) {
return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name);
}
public function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) {
return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
}
public function pExpr_ShellExec(Expr\ShellExec $node) {
protected function pExpr_ShellExec(Expr\ShellExec $node) {
return '`' . $this->pEncapsList($node->parts, '`') . '`';
}
public function pExpr_Closure(Expr\Closure $node) {
protected function pExpr_Closure(Expr\Closure $node) {
return ($node->static ? 'static ' : '')
. 'function ' . ($node->byRef ? '&' : '')
. '(' . $this->pCommaSeparated($node->params) . ')'
@ -526,11 +521,11 @@ class Standard extends PrettyPrinterAbstract
. ' {' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pExpr_ClosureUse(Expr\ClosureUse $node) {
protected function pExpr_ClosureUse(Expr\ClosureUse $node) {
return ($node->byRef ? '&' : '') . '$' . $node->var;
}
public function pExpr_New(Expr\New_ $node) {
protected function pExpr_New(Expr\New_ $node) {
if ($node->class instanceof Stmt\Class_) {
$args = $node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : '';
return 'new ' . $this->pClassCommon($node->class, $args);
@ -538,11 +533,11 @@ class Standard extends PrettyPrinterAbstract
return 'new ' . $this->p($node->class) . '(' . $this->pCommaSeparated($node->args) . ')';
}
public function pExpr_Clone(Expr\Clone_ $node) {
protected function pExpr_Clone(Expr\Clone_ $node) {
return 'clone ' . $this->p($node->expr);
}
public function pExpr_Ternary(Expr\Ternary $node) {
protected function pExpr_Ternary(Expr\Ternary $node) {
// a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.
// this is okay because the part between ? and : never needs parentheses.
return $this->pInfixOp('Expr_Ternary',
@ -550,13 +545,13 @@ class Standard extends PrettyPrinterAbstract
);
}
public function pExpr_Exit(Expr\Exit_ $node) {
protected function pExpr_Exit(Expr\Exit_ $node) {
$kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE);
return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die')
. (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : '');
}
public function pExpr_Yield(Expr\Yield_ $node) {
protected function pExpr_Yield(Expr\Yield_ $node) {
if ($node->value === null) {
return 'yield';
} else {
@ -570,7 +565,7 @@ class Standard extends PrettyPrinterAbstract
// Declarations
public function pStmt_Namespace(Stmt\Namespace_ $node) {
protected function pStmt_Namespace(Stmt\Namespace_ $node) {
if ($this->canUseSemicolonNamespaces) {
return 'namespace ' . $this->p($node->name) . ';' . "\n" . $this->pStmts($node->stmts, false);
} else {
@ -579,17 +574,17 @@ class Standard extends PrettyPrinterAbstract
}
}
public function pStmt_Use(Stmt\Use_ $node) {
protected function pStmt_Use(Stmt\Use_ $node) {
return 'use ' . $this->pUseType($node->type)
. $this->pCommaSeparated($node->uses) . ';';
}
public function pStmt_GroupUse(Stmt\GroupUse $node) {
protected function pStmt_GroupUse(Stmt\GroupUse $node) {
return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix)
. '\{' . $this->pCommaSeparated($node->uses) . '};';
}
public function pStmt_UseUse(Stmt\UseUse $node) {
protected function pStmt_UseUse(Stmt\UseUse $node) {
return $this->pUseType($node->type) . $this->p($node->name)
. ($node->name->getLast() !== $node->alias ? ' as ' . $node->alias : '');
}
@ -599,34 +594,34 @@ class Standard extends PrettyPrinterAbstract
: ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : '');
}
public function pStmt_Interface(Stmt\Interface_ $node) {
protected function pStmt_Interface(Stmt\Interface_ $node) {
return 'interface ' . $node->name
. (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
. "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Class(Stmt\Class_ $node) {
protected function pStmt_Class(Stmt\Class_ $node) {
return $this->pClassCommon($node, ' ' . $node->name);
}
public function pStmt_Trait(Stmt\Trait_ $node) {
protected function pStmt_Trait(Stmt\Trait_ $node) {
return 'trait ' . $node->name
. "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_TraitUse(Stmt\TraitUse $node) {
protected function pStmt_TraitUse(Stmt\TraitUse $node) {
return 'use ' . $this->pCommaSeparated($node->traits)
. (empty($node->adaptations)
? ';'
: ' {' . $this->pStmts($node->adaptations) . "\n" . '}');
}
public function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) {
protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) {
return $this->p($node->trait) . '::' . $node->method
. ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';';
}
public function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) {
protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) {
return (null !== $node->trait ? $this->p($node->trait) . '::' : '')
. $node->method . ' as'
. (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '')
@ -634,17 +629,17 @@ class Standard extends PrettyPrinterAbstract
. ';';
}
public function pStmt_Property(Stmt\Property $node) {
return (0 === $node->type ? 'var ' : $this->pModifiers($node->type)) . $this->pCommaSeparated($node->props) . ';';
protected function pStmt_Property(Stmt\Property $node) {
return (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) . $this->pCommaSeparated($node->props) . ';';
}
public function pStmt_PropertyProperty(Stmt\PropertyProperty $node) {
protected function pStmt_PropertyProperty(Stmt\PropertyProperty $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_ClassMethod(Stmt\ClassMethod $node) {
return $this->pModifiers($node->type)
protected function pStmt_ClassMethod(Stmt\ClassMethod $node) {
return $this->pModifiers($node->flags)
. 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->returnType ? ' : ' . $this->pType($node->returnType) : '')
@ -653,49 +648,50 @@ class Standard extends PrettyPrinterAbstract
: ';');
}
public function pStmt_ClassConst(Stmt\ClassConst $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
protected function pStmt_ClassConst(Stmt\ClassConst $node) {
return $this->pModifiers($node->flags)
. 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Function(Stmt\Function_ $node) {
protected function pStmt_Function(Stmt\Function_ $node) {
return 'function ' . ($node->byRef ? '&' : '') . $node->name
. '(' . $this->pCommaSeparated($node->params) . ')'
. (null !== $node->returnType ? ' : ' . $this->pType($node->returnType) : '')
. "\n" . '{' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Const(Stmt\Const_ $node) {
protected function pStmt_Const(Stmt\Const_ $node) {
return 'const ' . $this->pCommaSeparated($node->consts) . ';';
}
public function pStmt_Declare(Stmt\Declare_ $node) {
protected function pStmt_Declare(Stmt\Declare_ $node) {
return 'declare (' . $this->pCommaSeparated($node->declares) . ')'
. (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . "\n" . '}' : ';');
}
public function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) {
protected function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) {
return $node->key . '=' . $this->p($node->value);
}
// Control flow
public function pStmt_If(Stmt\If_ $node) {
protected function pStmt_If(Stmt\If_ $node) {
return 'if (' . $this->p($node->cond) . ') {'
. $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->elseifs)
. (null !== $node->else ? $this->p($node->else) : '');
}
public function pStmt_ElseIf(Stmt\ElseIf_ $node) {
protected function pStmt_ElseIf(Stmt\ElseIf_ $node) {
return ' elseif (' . $this->p($node->cond) . ') {'
. $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Else(Stmt\Else_ $node) {
protected function pStmt_Else(Stmt\Else_ $node) {
return ' else {' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_For(Stmt\For_ $node) {
protected function pStmt_For(Stmt\For_ $node) {
return 'for ('
. $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '')
. $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '')
@ -703,102 +699,104 @@ class Standard extends PrettyPrinterAbstract
. ') {' . $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Foreach(Stmt\Foreach_ $node) {
protected function pStmt_Foreach(Stmt\Foreach_ $node) {
return 'foreach (' . $this->p($node->expr) . ' as '
. (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')
. ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'
. $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_While(Stmt\While_ $node) {
protected function pStmt_While(Stmt\While_ $node) {
return 'while (' . $this->p($node->cond) . ') {'
. $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Do(Stmt\Do_ $node) {
protected function pStmt_Do(Stmt\Do_ $node) {
return 'do {' . $this->pStmts($node->stmts) . "\n"
. '} while (' . $this->p($node->cond) . ');';
}
public function pStmt_Switch(Stmt\Switch_ $node) {
protected function pStmt_Switch(Stmt\Switch_ $node) {
return 'switch (' . $this->p($node->cond) . ') {'
. $this->pStmts($node->cases) . "\n" . '}';
}
public function pStmt_Case(Stmt\Case_ $node) {
protected function pStmt_Case(Stmt\Case_ $node) {
return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'
. $this->pStmts($node->stmts);
}
public function pStmt_TryCatch(Stmt\TryCatch $node) {
protected function pStmt_TryCatch(Stmt\TryCatch $node) {
return 'try {' . $this->pStmts($node->stmts) . "\n" . '}'
. $this->pImplode($node->catches)
. ($node->finallyStmts !== null
? ' finally {' . $this->pStmts($node->finallyStmts) . "\n" . '}'
: '');
. ($node->finally !== null ? $this->p($node->finally) : '');
}
public function pStmt_Catch(Stmt\Catch_ $node) {
return ' catch (' . $this->p($node->type) . ' $' . $node->var . ') {'
protected function pStmt_Catch(Stmt\Catch_ $node) {
return ' catch (' . $this->pImplode($node->types, '|') . ' $' . $node->var . ') {'
. $this->pStmts($node->stmts) . "\n" . '}';
}
public function pStmt_Break(Stmt\Break_ $node) {
protected function pStmt_Finally(Stmt\Finally_ $node) {
return ' finally {' . $this->pStmts($node->stmts) . "\n" . '}';
}
protected function pStmt_Break(Stmt\Break_ $node) {
return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Continue(Stmt\Continue_ $node) {
protected function pStmt_Continue(Stmt\Continue_ $node) {
return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
}
public function pStmt_Return(Stmt\Return_ $node) {
protected function pStmt_Return(Stmt\Return_ $node) {
return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';';
}
public function pStmt_Throw(Stmt\Throw_ $node) {
protected function pStmt_Throw(Stmt\Throw_ $node) {
return 'throw ' . $this->p($node->expr) . ';';
}
public function pStmt_Label(Stmt\Label $node) {
protected function pStmt_Label(Stmt\Label $node) {
return $node->name . ':';
}
public function pStmt_Goto(Stmt\Goto_ $node) {
protected function pStmt_Goto(Stmt\Goto_ $node) {
return 'goto ' . $node->name . ';';
}
// Other
public function pStmt_Echo(Stmt\Echo_ $node) {
protected function pStmt_Echo(Stmt\Echo_ $node) {
return 'echo ' . $this->pCommaSeparated($node->exprs) . ';';
}
public function pStmt_Static(Stmt\Static_ $node) {
protected function pStmt_Static(Stmt\Static_ $node) {
return 'static ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_Global(Stmt\Global_ $node) {
protected function pStmt_Global(Stmt\Global_ $node) {
return 'global ' . $this->pCommaSeparated($node->vars) . ';';
}
public function pStmt_StaticVar(Stmt\StaticVar $node) {
protected function pStmt_StaticVar(Stmt\StaticVar $node) {
return '$' . $node->name
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
}
public function pStmt_Unset(Stmt\Unset_ $node) {
protected function pStmt_Unset(Stmt\Unset_ $node) {
return 'unset(' . $this->pCommaSeparated($node->vars) . ');';
}
public function pStmt_InlineHTML(Stmt\InlineHTML $node) {
protected function pStmt_InlineHTML(Stmt\InlineHTML $node) {
return '?>' . $this->pNoIndent("\n" . $node->value) . '<?php ';
}
public function pStmt_HaltCompiler(Stmt\HaltCompiler $node) {
protected function pStmt_HaltCompiler(Stmt\HaltCompiler $node) {
return '__halt_compiler();' . $node->remaining;
}
public function pStmt_Nop(Stmt\Nop $node) {
protected function pStmt_Nop(Stmt\Nop $node) {
return '';
}
@ -809,7 +807,7 @@ class Standard extends PrettyPrinterAbstract
}
protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) {
return $this->pModifiers($node->type)
return $this->pModifiers($node->flags)
. 'class' . $afterClassToken
. (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
. (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')

View File

@ -265,7 +265,11 @@ abstract class PrettyPrinterAbstract
protected function pImplode(array $nodes, $glue = '') {
$pNodes = array();
foreach ($nodes as $node) {
$pNodes[] = $this->p($node);
if (null === $node) {
$pNodes[] = '';
} else {
$pNodes[] = $this->p($node);
}
}
return implode($glue, $pNodes);

View File

@ -27,7 +27,7 @@ class TraitTest extends \PHPUnit_Framework_TestCase
->addStmt($prop)
->getNode();
$this->assertEquals(new Stmt\Trait_('TestTrait', array(
$prop, $method1, $method2, $method3
'stmts' => array($prop, $method1, $method2, $method3)
), array(
'comments' => array(
new Comment\Doc('/** Nice trait */')

View File

@ -11,13 +11,6 @@ class CommentTest extends \PHPUnit_Framework_TestCase
$this->assertSame('/* Some comment */', (string) $comment);
$this->assertSame(1, $comment->getLine());
$this->assertSame(10, $comment->getFilePos());
$comment->setText('/* Some other comment */');
$comment->setLine(10);
$this->assertSame('/* Some other comment */', $comment->getText());
$this->assertSame('/* Some other comment */', (string) $comment);
$this->assertSame(10, $comment->getLine());
}
/**

View File

@ -30,51 +30,6 @@ class NameTest extends \PHPUnit_Framework_TestCase
$this->assertSame('foo_bar', $name->toString('_'));
}
public function testSet() {
$name = new Name('foo');
$name->set('foo\bar');
$this->assertSame('foo\bar', $name->toString());
$name->set(array('foo', 'bar'));
$this->assertSame('foo\bar', $name->toString());
$name->set(new Name('foo\bar'));
$this->assertSame('foo\bar', $name->toString());
}
public function testSetFirst() {
$name = new Name('foo');
$name->setFirst('bar');
$this->assertSame('bar', $name->toString());
$name->setFirst('A\B');
$this->assertSame('A\B', $name->toString());
$name->setFirst('C');
$this->assertSame('C\B', $name->toString());
$name->setFirst('D\E');
$this->assertSame('D\E\B', $name->toString());
}
public function testSetLast() {
$name = new Name('foo');
$name->setLast('bar');
$this->assertSame('bar', $name->toString());
$name->setLast('A\B');
$this->assertSame('A\B', $name->toString());
$name->setLast('C');
$this->assertSame('A\C', $name->toString());
$name->setLast('D\E');
$this->assertSame('A\D\E', $name->toString());
}
public function testAppend() {
$name = new Name('foo');
@ -96,20 +51,53 @@ class NameTest extends \PHPUnit_Framework_TestCase
}
public function testSlice() {
$name = new Name('foo\bar');
$this->assertEquals(new Name('foo\bar'), $name->slice(0));
$this->assertEquals(new Name('bar'), $name->slice(1));
$this->assertEquals(new Name([]), $name->slice(2));
$name = new Name('foo\bar\baz');
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(0));
$this->assertEquals(new Name('bar\baz'), $name->slice(1));
$this->assertEquals(new Name([]), $name->slice(3));
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(-3));
$this->assertEquals(new Name('bar\baz'), $name->slice(-2));
$this->assertEquals(new Name('foo\bar'), $name->slice(0, -1));
$this->assertEquals(new Name([]), $name->slice(0, -3));
$this->assertEquals(new Name('bar'), $name->slice(1, -1));
$this->assertEquals(new Name([]), $name->slice(1, -2));
$this->assertEquals(new Name('bar'), $name->slice(-2, 1));
$this->assertEquals(new Name('bar'), $name->slice(-2, -1));
$this->assertEquals(new Name([]), $name->slice(-2, -2));
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Offset 4 is out of bounds
*/
public function testSliceException() {
public function testSliceOffsetTooLarge() {
(new Name('foo\bar\baz'))->slice(4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Offset -4 is out of bounds
*/
public function testSliceOffsetTooSmall() {
(new Name('foo\bar\baz'))->slice(-4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Length 4 is out of bounds
*/
public function testSliceLengthTooLarge() {
(new Name('foo\bar\baz'))->slice(0, 4);
}
/**
* @expectedException \OutOfBoundsException
* @expectedExceptionMessage Length -4 is out of bounds
*/
public function testSliceLengthTooSmall() {
(new Name('foo\bar\baz'))->slice(0, -4);
}
public function testConcat() {
$this->assertEquals(new Name('foo\bar\baz'), Name::concat('foo', 'bar\baz'));
$this->assertEquals(
@ -159,6 +147,6 @@ class NameTest extends \PHPUnit_Framework_TestCase
*/
public function testInvalidArg() {
$name = new Name('foo');
$name->set(new \stdClass);
$name->append(new \stdClass);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace PhpParser\Node\Stmt;
class ClassConstTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider provideModifiers
*/
public function testModifiers($modifier) {
$node = new ClassConst(
array(), // invalid
constant('PhpParser\Node\Stmt\Class_::MODIFIER_' . strtoupper($modifier))
);
$this->assertTrue($node->{'is' . $modifier}());
}
public function testNoModifiers() {
$node = new ClassConst(array(), 0);
$this->assertTrue($node->isPublic());
$this->assertFalse($node->isProtected());
$this->assertFalse($node->isPrivate());
$this->assertFalse($node->isStatic());
}
public function provideModifiers() {
return array(
array('public'),
array('protected'),
array('private'),
);
}
}

View File

@ -56,4 +56,11 @@ class ClassTest extends \PHPUnit_Framework_TestCase
$this->assertSame($methodTest, $class->getMethod('test'));
$this->assertNull($class->getMethod('nonExisting'));
}
public function testDeprecatedTypeNode() {
$class = new Class_('Foo', array('type' => Class_::MODIFIER_ABSTRACT));
$this->assertTrue($class->isAbstract());
$this->assertSame(Class_::MODIFIER_ABSTRACT, $class->flags);
$this->assertSame(Class_::MODIFIER_ABSTRACT, $class->type);
}
}

View File

@ -0,0 +1,144 @@
Array destructuring
-----
<?php
[$a, $b] = [$c, $d];
[, $a, , , $b, ,] = $foo;
[, [[$a]], $b] = $bar;
['a' => $b, 'b' => $a] = $baz;
-----
!!php7
array(
0: Expr_Assign(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
)
)
expr: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: c
)
byRef: false
)
1: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: d
)
byRef: false
)
)
)
)
1: Expr_Assign(
var: Expr_Array(
items: array(
0: null
1: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
2: null
3: null
4: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
5: null
)
)
expr: Expr_Variable(
name: foo
)
)
2: Expr_Assign(
var: Expr_Array(
items: array(
0: null
1: Expr_ArrayItem(
key: null
value: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
)
)
byRef: false
)
)
)
byRef: false
)
2: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
)
)
expr: Expr_Variable(
name: bar
)
)
3: Expr_Assign(
var: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: Scalar_String(
value: a
)
value: Expr_Variable(
name: b
)
byRef: false
)
1: Expr_ArrayItem(
key: Scalar_String(
value: b
)
value: Expr_Variable(
name: a
)
byRef: false
)
)
)
expr: Expr_Variable(
name: baz
)
)
)

View File

@ -207,9 +207,13 @@ array(
)
16: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
)
comments: array(
@ -225,13 +229,21 @@ array(
)
17: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
1: null
2: Expr_Variable(
name: b
2: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
)
)
@ -241,20 +253,32 @@ array(
)
18: Expr_Assign(
var: Expr_List(
vars: array(
0: Expr_Variable(
name: a
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
1: Expr_List(
vars: array(
items: array(
0: null
1: Expr_Variable(
name: c
1: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: c
)
byRef: false
)
)
)
2: Expr_Variable(
name: d
2: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: d
)
byRef: false
)
)
)

View File

@ -12,25 +12,25 @@ array(
expr: Scalar_String(
value: A.php
)
type: 1
type: TYPE_INCLUDE (1)
)
1: Expr_Include(
expr: Scalar_String(
value: A.php
)
type: 2
type: TYPE_INCLUDE_ONCE (2)
)
2: Expr_Include(
expr: Scalar_String(
value: A.php
)
type: 3
type: TYPE_REQUIRE (3)
)
3: Expr_Include(
expr: Scalar_String(
value: A.php
)
type: 4
type: TYPE_REQURE_ONCE (4)
)
4: Expr_Eval(
expr: Scalar_String(

View File

@ -0,0 +1,75 @@
List destructing with keys
-----
<?php
list('a' => $b) = ['a' => 'b'];
list('a' => list($b => $c), 'd' => $e) = $x;
-----
!!php7
array(
0: Expr_Assign(
var: Expr_List(
items: array(
0: Expr_ArrayItem(
key: Scalar_String(
value: a
)
value: Expr_Variable(
name: b
)
byRef: false
)
)
)
expr: Expr_Array(
items: array(
0: Expr_ArrayItem(
key: Scalar_String(
value: a
)
value: Scalar_String(
value: b
)
byRef: false
)
)
)
)
1: Expr_Assign(
var: Expr_List(
items: array(
0: Expr_ArrayItem(
key: Scalar_String(
value: a
)
value: Expr_List(
items: array(
0: Expr_ArrayItem(
key: Expr_Variable(
name: b
)
value: Expr_Variable(
name: c
)
byRef: false
)
)
)
byRef: false
)
1: Expr_ArrayItem(
key: Scalar_String(
value: d
)
value: Expr_Variable(
name: e
)
byRef: false
)
)
)
expr: Expr_Variable(
name: x
)
)
)

View File

@ -54,14 +54,14 @@ class Foo {
-----
array(
0: Stmt_Class(
type: 0
flags: 0
name: Test
extends: null
implements: array(
)
stmts: array(
0: Stmt_ClassMethod(
type: 0
flags: 0
byRef: false
name: array
params: array(
@ -71,7 +71,7 @@ array(
)
)
1: Stmt_ClassMethod(
type: 0
flags: 0
byRef: false
name: public
params: array(
@ -81,7 +81,7 @@ array(
)
)
2: Stmt_ClassMethod(
type: 8
flags: MODIFIER_STATIC (8)
byRef: false
name: list
params: array(
@ -91,7 +91,7 @@ array(
)
)
3: Stmt_ClassMethod(
type: 8
flags: MODIFIER_STATIC (8)
byRef: false
name: protected
params: array(
@ -101,7 +101,7 @@ array(
)
)
4: Stmt_Property(
type: 1
flags: MODIFIER_PUBLIC (1)
props: array(
0: Stmt_PropertyProperty(
name: class
@ -110,7 +110,7 @@ array(
)
)
5: Stmt_Property(
type: 1
flags: MODIFIER_PUBLIC (1)
props: array(
0: Stmt_PropertyProperty(
name: private
@ -119,6 +119,7 @@ array(
)
)
6: Stmt_ClassConst(
flags: 0
consts: array(
0: Const(
name: TRAIT
@ -135,6 +136,7 @@ array(
)
)
7: Stmt_ClassConst(
flags: 0
consts: array(
0: Const(
name: __CLASS__
@ -267,7 +269,7 @@ array(
name: FINAL
)
10: Stmt_Class(
type: 0
flags: 0
name: Foo
extends: null
implements: array(
@ -319,7 +321,7 @@ array(
)
)
method: throw
newModifier: 2
newModifier: MODIFIER_PROTECTED (2)
newName: public
)
3: Stmt_TraitUseAdaptation_Alias(
@ -329,7 +331,7 @@ array(
)
)
method: self
newModifier: 2
newModifier: MODIFIER_PROTECTED (2)
newName: null
)
4: Stmt_TraitUseAdaptation_Alias(

View File

@ -9,14 +9,14 @@ abstract class A {
-----
array(
0: Stmt_Class(
type: 16
flags: MODIFIER_ABSTRACT (16)
name: A
extends: null
implements: array(
)
stmts: array(
0: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: a
params: array(
@ -26,7 +26,7 @@ array(
)
)
1: Stmt_ClassMethod(
type: 17
flags: MODIFIER_PUBLIC | MODIFIER_ABSTRACT (17)
byRef: false
name: b
params: array(
@ -36,4 +36,4 @@ array(
)
)
)
)
)

View File

@ -24,14 +24,14 @@ class A {
array(
0: Expr_New(
class: Stmt_Class(
type: 0
flags: 0
name: null
extends: null
implements: array(
)
stmts: array(
0: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: test
params: array(
@ -47,7 +47,7 @@ array(
)
1: Expr_New(
class: Stmt_Class(
type: 0
flags: 0
name: null
extends: Name(
parts: array(
@ -74,14 +74,14 @@ array(
)
2: Expr_New(
class: Stmt_Class(
type: 0
flags: 0
name: null
extends: null
implements: array(
)
stmts: array(
0: Stmt_Property(
type: 1
flags: MODIFIER_PUBLIC (1)
props: array(
0: Stmt_PropertyProperty(
name: foo
@ -96,7 +96,7 @@ array(
)
3: Expr_New(
class: Stmt_Class(
type: 0
flags: 0
name: null
extends: Name(
parts: array(
@ -137,14 +137,14 @@ array(
)
)
4: Stmt_Class(
type: 0
flags: 0
name: A
extends: null
implements: array(
)
stmts: array(
0: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: test
params: array(
@ -154,7 +154,7 @@ array(
0: Stmt_Return(
expr: Expr_New(
class: Stmt_Class(
type: 0
flags: 0
name: null
extends: Name(
parts: array(
@ -165,6 +165,7 @@ array(
)
stmts: array(
0: Stmt_ClassConst(
flags: 0
consts: array(
0: Const(
name: A
@ -191,4 +192,4 @@ array(
)
)
)
)
)

View File

@ -17,7 +17,7 @@ array(
)
stmts: array(
0: Stmt_Class(
type: 0
flags: 0
name: A
extends: null
implements: array(

View File

@ -0,0 +1,32 @@
Invalid class constant modifiers
-----
<?php
class A {
static const X = 1;
}
-----
!!php7
Cannot use 'static' as constant modifier on line 3
-----
<?php
class A {
abstract const X = 1;
}
-----
!!php7
Cannot use 'abstract' as constant modifier on line 3
-----
<?php
class A {
final const X = 1;
}
-----
!!php7
Cannot use 'final' as constant modifier on line 3
-----
<?php
class A {
public public const X = 1;
}
-----
Multiple access type modifiers are not allowed on line 3

View File

@ -0,0 +1,67 @@
Class constant modifiers
-----
<?php
class Foo {
const A = 1;
public const B = 2;
protected const C = 3;
private const D = 4;
}
-----
!!php7
array(
0: Stmt_Class(
flags: 0
name: Foo
extends: null
implements: array(
)
stmts: array(
0: Stmt_ClassConst(
flags: 0
consts: array(
0: Const(
name: A
value: Scalar_LNumber(
value: 1
)
)
)
)
1: Stmt_ClassConst(
flags: MODIFIER_PUBLIC (1)
consts: array(
0: Const(
name: B
value: Scalar_LNumber(
value: 2
)
)
)
)
2: Stmt_ClassConst(
flags: MODIFIER_PROTECTED (2)
consts: array(
0: Const(
name: C
value: Scalar_LNumber(
value: 3
)
)
)
)
3: Stmt_ClassConst(
flags: MODIFIER_PRIVATE (4)
consts: array(
0: Const(
name: D
value: Scalar_LNumber(
value: 4
)
)
)
)
)
)
)

View File

@ -6,7 +6,7 @@ final class A {}
-----
array(
0: Stmt_Class(
type: 32
flags: MODIFIER_FINAL (32)
name: A
extends: null
implements: array(

View File

@ -14,14 +14,14 @@ abstract class A {
-----
array(
0: Stmt_Class(
type: 16
flags: MODIFIER_ABSTRACT (16)
name: A
extends: null
implements: array(
)
stmts: array(
0: Stmt_Property(
type: 0
flags: 0
props: array(
0: Stmt_PropertyProperty(
name: a
@ -30,7 +30,7 @@ array(
)
)
1: Stmt_Property(
type: 8
flags: MODIFIER_STATIC (8)
props: array(
0: Stmt_PropertyProperty(
name: b
@ -39,7 +39,7 @@ array(
)
)
2: Stmt_ClassMethod(
type: 16
flags: MODIFIER_ABSTRACT (16)
byRef: false
name: c
params: array(
@ -48,7 +48,7 @@ array(
stmts: null
)
3: Stmt_ClassMethod(
type: 32
flags: MODIFIER_FINAL (32)
byRef: false
name: d
params: array(
@ -58,7 +58,7 @@ array(
)
)
4: Stmt_ClassMethod(
type: 8
flags: MODIFIER_STATIC (8)
byRef: false
name: e
params: array(
@ -68,7 +68,7 @@ array(
)
)
5: Stmt_ClassMethod(
type: 40
flags: MODIFIER_STATIC | MODIFIER_FINAL (40)
byRef: false
name: f
params: array(
@ -78,7 +78,7 @@ array(
)
)
6: Stmt_ClassMethod(
type: 0
flags: 0
byRef: false
name: g
params: array(
@ -89,4 +89,4 @@ array(
)
)
)
)
)

View File

@ -23,7 +23,7 @@ array(
)
stmts: array(
0: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: a
params: array(
@ -33,4 +33,4 @@ array(
)
)
)
)
)

View File

@ -30,7 +30,7 @@ Cannot use the final modifier on an abstract class member on line 1
Syntax error, unexpected T_FINAL, expecting T_CLASS from 1:16 to 1:20
array(
0: Stmt_Class(
type: 32
flags: MODIFIER_FINAL (32)
name: A
extends: null
implements: array(

View File

@ -10,14 +10,14 @@ class A {
-----
array(
0: Stmt_Class(
type: 0
flags: 0
name: A
extends: null
implements: array(
)
stmts: array(
0: Stmt_Property(
type: 0
flags: 0
props: array(
0: Stmt_PropertyProperty(
name: foo
@ -26,7 +26,7 @@ array(
)
)
1: Stmt_ClassMethod(
type: 0
flags: 0
byRef: false
name: bar
params: array(
@ -36,7 +36,7 @@ array(
)
)
2: Stmt_ClassMethod(
type: 24
flags: MODIFIER_ABSTRACT | MODIFIER_STATIC (24)
byRef: false
name: baz
params: array(
@ -47,4 +47,4 @@ array(
)
)
)
)
)

View File

@ -18,7 +18,7 @@ class A extends B implements C, D {
-----
array(
0: Stmt_Class(
type: 0
flags: 0
name: A
extends: Name(
parts: array(
@ -39,6 +39,7 @@ array(
)
stmts: array(
0: Stmt_ClassConst(
flags: 0
consts: array(
0: Const(
name: A
@ -55,7 +56,7 @@ array(
)
)
1: Stmt_Property(
type: 1
flags: MODIFIER_PUBLIC (1)
props: array(
0: Stmt_PropertyProperty(
name: a
@ -72,7 +73,7 @@ array(
)
)
2: Stmt_Property(
type: 2
flags: MODIFIER_PROTECTED (2)
props: array(
0: Stmt_PropertyProperty(
name: e
@ -81,7 +82,7 @@ array(
)
)
3: Stmt_Property(
type: 4
flags: MODIFIER_PRIVATE (4)
props: array(
0: Stmt_PropertyProperty(
name: f
@ -90,7 +91,7 @@ array(
)
)
4: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: a
params: array(
@ -100,7 +101,7 @@ array(
)
)
5: Stmt_ClassMethod(
type: 9
flags: MODIFIER_PUBLIC | MODIFIER_STATIC (9)
byRef: false
name: b
params: array(
@ -117,7 +118,7 @@ array(
)
)
6: Stmt_ClassMethod(
type: 33
flags: MODIFIER_PUBLIC | MODIFIER_FINAL (33)
byRef: false
name: c
params: array(
@ -131,7 +132,7 @@ array(
)
)
7: Stmt_ClassMethod(
type: 2
flags: MODIFIER_PROTECTED (2)
byRef: false
name: d
params: array(
@ -141,7 +142,7 @@ array(
)
)
8: Stmt_ClassMethod(
type: 4
flags: MODIFIER_PRIVATE (4)
byRef: false
name: e
params: array(
@ -152,4 +153,4 @@ array(
)
)
)
)
)

View File

@ -26,7 +26,7 @@ array(
name: A
stmts: array(
0: Stmt_ClassMethod(
type: 1
flags: MODIFIER_PUBLIC (1)
byRef: false
name: a
params: array(
@ -38,7 +38,7 @@ array(
)
)
1: Stmt_Class(
type: 0
flags: 0
name: B
extends: null
implements: array(
@ -67,7 +67,7 @@ array(
0: Stmt_TraitUseAdaptation_Alias(
trait: null
method: a
newModifier: 2
newModifier: MODIFIER_PROTECTED (2)
newName: b
)
1: Stmt_TraitUseAdaptation_Alias(
@ -79,7 +79,7 @@ array(
2: Stmt_TraitUseAdaptation_Alias(
trait: null
method: e
newModifier: 4
newModifier: MODIFIER_PRIVATE (4)
newName: null
)
)
@ -130,7 +130,7 @@ array(
)
)
method: b
newModifier: 2
newModifier: MODIFIER_PROTECTED (2)
newName: c
)
2: Stmt_TraitUseAdaptation_Alias(
@ -150,11 +150,11 @@ array(
)
)
method: f
newModifier: 4
newModifier: MODIFIER_PRIVATE (4)
newName: null
)
)
)
)
)
)
)

View File

@ -1,7 +1,7 @@
Scalar type declarations
-----
<?php
function test(bool $a, Int $b, FLOAT $c, StRiNg $d) {}
function test(bool $a, Int $b, FLOAT $c, StRiNg $d, iterable $e) : void {}
-----
!!php7
array(
@ -37,8 +37,15 @@ array(
name: d
default: null
)
4: Param(
type: iterable
byRef: false
variadic: false
name: e
default: null
)
)
returnType: null
returnType: void
stmts: array(
)
)

View File

@ -0,0 +1,47 @@
Nullable types
-----
<?php
function test(?Foo $bar, ?string $foo) : ?Baz {
}
-----
!!php7
array(
0: Stmt_Function(
byRef: false
name: test
params: array(
0: Param(
type: NullableType(
type: Name(
parts: array(
0: Foo
)
)
)
byRef: false
variadic: false
name: bar
default: null
)
1: Param(
type: NullableType(
type: string
)
byRef: false
variadic: false
name: foo
default: null
)
)
returnType: NullableType(
type: Name(
parts: array(
0: Baz
)
)
)
stmts: array(
)
)
)

View File

@ -80,12 +80,20 @@ array(
keyVar: null
byRef: false
valueVar: Expr_List(
vars: array(
0: Expr_Variable(
name: a
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: a
)
byRef: false
)
1: Expr_Variable(
name: b
1: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
)
)
@ -101,13 +109,21 @@ array(
)
byRef: false
valueVar: Expr_List(
vars: array(
0: Expr_Variable(
name: b
items: array(
0: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: b
)
byRef: false
)
1: null
2: Expr_Variable(
name: c
2: Expr_ArrayItem(
key: null
value: Expr_Variable(
name: c
)
byRef: false
)
)
)

View File

@ -0,0 +1,65 @@
Try/catch with multiple classes
-----
<?php
try {
$x;
} catch (X|Y $e1) {
$y;
} catch (\A|B\C $e2) {
$z;
}
-----
!!php7
array(
0: Stmt_TryCatch(
stmts: array(
0: Expr_Variable(
name: x
)
)
catches: array(
0: Stmt_Catch(
types: array(
0: Name(
parts: array(
0: X
)
)
1: Name(
parts: array(
0: Y
)
)
)
var: e1
stmts: array(
0: Expr_Variable(
name: y
)
)
)
1: Stmt_Catch(
types: array(
0: Name_FullyQualified(
parts: array(
0: A
)
)
1: Name(
parts: array(
0: B
1: C
)
)
)
var: e2
stmts: array(
0: Expr_Variable(
name: z
)
)
)
)
finally: null
)
)

View File

@ -18,10 +18,10 @@ use const foo\BAR as BAZ;
-----
array(
0: Stmt_Use(
type: 1
type: TYPE_NORMAL (1)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: A
@ -33,10 +33,10 @@ array(
)
)
1: Stmt_Use(
type: 1
type: TYPE_NORMAL (1)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: C
@ -48,10 +48,10 @@ array(
)
)
2: Stmt_Use(
type: 1
type: TYPE_NORMAL (1)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: F
@ -61,7 +61,7 @@ array(
alias: H
)
1: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: J
@ -72,10 +72,10 @@ array(
)
)
3: Stmt_Use(
type: 1
type: TYPE_NORMAL (1)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: A
@ -89,10 +89,10 @@ array(
)
)
4: Stmt_Use(
type: 1
type: TYPE_NORMAL (1)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: A
@ -103,10 +103,10 @@ array(
)
)
5: Stmt_Use(
type: 2
type: TYPE_FUNCTION (2)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: foo
@ -121,10 +121,10 @@ array(
)
)
6: Stmt_Use(
type: 2
type: TYPE_FUNCTION (2)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: foo
@ -136,10 +136,10 @@ array(
)
)
7: Stmt_Use(
type: 3
type: TYPE_CONSTANT (3)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: foo
@ -151,10 +151,10 @@ array(
)
)
8: Stmt_Use(
type: 3
type: TYPE_CONSTANT (3)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: foo

View File

@ -10,7 +10,7 @@ use A\B\{C\D, function b\c, const D};
-----
array(
0: Stmt_GroupUse(
type: 0
type: TYPE_UNKNOWN (0)
prefix: Name(
parts: array(
0: A
@ -18,7 +18,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: B
@ -29,7 +29,7 @@ array(
)
)
1: Stmt_GroupUse(
type: 0
type: TYPE_UNKNOWN (0)
prefix: Name(
parts: array(
0: A
@ -37,7 +37,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: B
@ -47,7 +47,7 @@ array(
alias: C
)
1: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: D
@ -58,7 +58,7 @@ array(
)
)
2: Stmt_GroupUse(
type: 0
type: TYPE_UNKNOWN (0)
prefix: Name(
parts: array(
0: A
@ -67,7 +67,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: C
@ -77,7 +77,7 @@ array(
alias: D
)
1: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: E
@ -88,7 +88,7 @@ array(
)
)
3: Stmt_GroupUse(
type: 2
type: TYPE_FUNCTION (2)
prefix: Name(
parts: array(
0: A
@ -96,7 +96,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: b
@ -106,7 +106,7 @@ array(
alias: c
)
1: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: d
@ -117,7 +117,7 @@ array(
)
)
4: Stmt_GroupUse(
type: 3
type: TYPE_CONSTANT (3)
prefix: Name(
parts: array(
0: A
@ -125,7 +125,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: B
@ -135,7 +135,7 @@ array(
alias: C
)
1: Stmt_UseUse(
type: 0
type: TYPE_UNKNOWN (0)
name: Name(
parts: array(
0: D
@ -146,7 +146,7 @@ array(
)
)
5: Stmt_GroupUse(
type: 0
type: TYPE_UNKNOWN (0)
prefix: Name(
parts: array(
0: A
@ -155,7 +155,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: C
@ -165,7 +165,7 @@ array(
alias: D
)
1: Stmt_UseUse(
type: 2
type: TYPE_FUNCTION (2)
name: Name(
parts: array(
0: b
@ -175,7 +175,7 @@ array(
alias: c
)
2: Stmt_UseUse(
type: 3
type: TYPE_CONSTANT (3)
name: Name(
parts: array(
0: D
@ -185,4 +185,4 @@ array(
)
)
)
)
)

View File

@ -8,7 +8,7 @@ use Bar\{Foo};
Syntax error, unexpected T_USE, expecting ';' from 4:1 to 4:3
array(
0: Stmt_GroupUse(
type: 0
type: TYPE_UNKNOWN (0)
prefix: Name(
parts: array(
0: Bar
@ -16,7 +16,7 @@ array(
)
uses: array(
0: Stmt_UseUse(
type: 1
type: TYPE_NORMAL (1)
name: Name(
parts: array(
0: Foo

View File

@ -36,9 +36,11 @@ array(
)
catches: array(
0: Stmt_Catch(
type: Name(
parts: array(
0: A
types: array(
0: Name(
parts: array(
0: A
)
)
)
var: b
@ -55,9 +57,11 @@ array(
)
)
1: Stmt_Catch(
type: Name(
parts: array(
0: B
types: array(
0: Name(
parts: array(
0: B
)
)
)
var: c
@ -74,14 +78,16 @@ array(
)
)
)
finallyStmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doFinally
finally: Stmt_Finally(
stmts: array(
0: Expr_FuncCall(
name: Name(
parts: array(
0: doFinally
)
)
args: array(
)
)
args: array(
)
)
)
@ -91,9 +97,11 @@ array(
)
catches: array(
0: Stmt_Catch(
type: Name(
parts: array(
0: A
types: array(
0: Name(
parts: array(
0: A
)
)
)
var: b
@ -101,7 +109,7 @@ array(
)
)
)
finallyStmts: null
finally: null
comments: array(
0: // no finally
)
@ -111,7 +119,9 @@ array(
)
catches: array(
)
finallyStmts: array(
finally: Stmt_Finally(
stmts: array(
)
)
comments: array(
0: // no catch

View File

@ -0,0 +1,14 @@
Array destructuring
-----
<?php
[$a, $b] = [$c, $d];
[, $a, , , $b, ,] = $foo;
[, [[$a]], $b] = $bar;
['a' => $b, 'b' => $a] = $baz;
-----
!!php7
[$a, $b] = [$c, $d];
[, $a, , , $b, ] = $foo;
[, [[$a]], $b] = $bar;
['a' => $b, 'b' => $a] = $baz;

View File

@ -0,0 +1,20 @@
Class constants
-----
<?php
class Foo
{
const A = 1, B = 2;
public const C = 3, D = 4;
protected const E = 5, F = 6;
private const G = 7, H = 8;
}
-----
!!php7
class Foo
{
const A = 1, B = 2;
public const C = 3, D = 4;
protected const E = 5, F = 6;
private const G = 7, H = 8;
}

View File

@ -0,0 +1,19 @@
Multi catch
-----
<?php
try {
$x;
} catch (X|Y $e1) {
$y;
} catch (\A|B\C $e2) {
$z;
}
-----
!!php7
try {
$x;
} catch (X|Y $e1) {
$y;
} catch (\A|B\C $e2) {
$z;
}

View File

@ -0,0 +1,11 @@
Nullable types
-----
<?php
function test(?Foo $bar, ?string $foo) : ?Baz
{
}
-----
!!php7
function test(?Foo $bar, ?string $foo) : ?Baz
{
}