mirror of
https://github.com/nikic/PHP-Parser.git
synced 2025-07-26 17:00:48 +02:00
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
447a020a1f | ||
|
45f70ed80a | ||
|
74a361814d | ||
|
6478c5ac53 | ||
|
8bb415902e | ||
|
48fd76e542 | ||
|
d20a197ca7 | ||
|
62dee28027 | ||
|
b396e9e0d6 | ||
|
f212bb7afb | ||
|
f43324a074 | ||
|
73b160f8c4 | ||
|
4f9dc8b0f5 | ||
|
469377f4a8 | ||
|
74d3f7fc24 | ||
|
25828ea952 | ||
|
05ed79595b | ||
|
954f7a411f | ||
|
8eea230464 | ||
|
9c7a3f8d8f | ||
|
26573ea64f | ||
|
3abf7425cd | ||
|
961f158f6d | ||
|
e50c67b7a9 | ||
|
26a0197186 | ||
|
aedfcc23cd | ||
|
8d09ba87f4 | ||
|
23c79fbbfb | ||
|
b9c8374498 | ||
|
d0826bd3e4 | ||
|
5ea6c2938b | ||
|
b493c51cce | ||
|
54139ca49b | ||
|
cde9bab3bb | ||
|
018da15f3a | ||
|
ba14437165 | ||
|
4a22c15169 | ||
|
514f71024e | ||
|
6a97061265 | ||
|
e3f223f623 | ||
|
03caf4cc99 | ||
|
b11fc12cce | ||
|
3beee6ec77 | ||
|
58de479119 | ||
|
d3ae2ed679 | ||
|
beba9c528f | ||
|
fadccead52 | ||
|
d8235a2701 | ||
|
5973c30a46 | ||
|
b917ba7b9c | ||
|
caf540443a |
.github/workflows
CHANGELOG.mdMakefileREADME.mddoc
grammar
lib/PhpParser
Builder
BuilderFactory.phpBuilderHelpers.phpInternal
Lexer
Emulative.php
Modifiers.phpNameContext.phpTokenEmulator
Node
NodeDumper.phpNodeTraverser.phpNodeVisitor
Parser
ParserAbstract.phpPhpVersion.phpPrettyPrinter
PrettyPrinterAbstract.phpcompatibility_tokens.phptest
PhpParser
Builder
BuilderHelpersTest.phpLexer
ModifiersTest.phpNode
NodeAbstractTest.phpNodeVisitor
PrettyPrinterTest.phpcode
formatPreservation
parser
commentAtEndOfClass.test
errorHandling
expr
alternative_array_syntax.testarrow_function.testclosure.testexit.test
fetchAndCall
new.testnewDeref.testuvs
scalar
semiReserved.teststmt
attributes.test
class
anonymous.testasymmetric_visibility.testimplicitPublic.testmodifier_error.testphp4Style.testpropertyTypes.testproperty_hooks.testproperty_modifiers.testproperty_promotion.testsimple.test
function
builtinTypeDeclarations.testbyRef.testdefaultValues.testdisjointNormalFormTypes.testexit_die_function.testintersectionTypes.testnullableTypes.testparameters_trailing_comma.testtypeDeclarations.testtypeVersions.testunionTypes.testvariadic.testvariadicDefaultValue.test
namespace
newInInitializer.testprettyPrinter
fixtures
test_old
tools/fuzzing
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@@ -38,6 +38,8 @@ jobs:
|
||||
- "8.1"
|
||||
- "8.2"
|
||||
- "8.3"
|
||||
- "8.4"
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
@@ -54,7 +56,7 @@ jobs:
|
||||
run: "php vendor/bin/phpunit"
|
||||
test_old_73_80:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: "PHP 7.4 Code on PHP 8.3 Integration Tests"
|
||||
name: "PHP 7.4 Code on PHP 8.4 Integration Tests"
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
@@ -62,7 +64,7 @@ jobs:
|
||||
uses: "shivammathur/setup-php@v2"
|
||||
with:
|
||||
coverage: "none"
|
||||
php-version: "8.3"
|
||||
php-version: "8.4"
|
||||
ini-file: "development"
|
||||
tools: composer:v2
|
||||
- name: "Install PHP 8 dependencies"
|
||||
@@ -71,7 +73,7 @@ jobs:
|
||||
run: "test_old/run-php-src.sh 7.4.33"
|
||||
test_old_80_70:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: "PHP 8.3 Code on PHP 7.4 Integration Tests"
|
||||
name: "PHP 8.4 Code on PHP 7.4 Integration Tests"
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: "actions/checkout@v4"
|
||||
@@ -85,7 +87,7 @@ jobs:
|
||||
- name: "Install PHP 8 dependencies"
|
||||
run: "COMPOSER_ROOT_VERSION=dev-master composer update --no-progress --prefer-dist"
|
||||
- name: "Tests"
|
||||
run: "test_old/run-php-src.sh 8.3.0RC2"
|
||||
run: "test_old/run-php-src.sh 8.4.0beta5"
|
||||
phpstan:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: "PHPStan"
|
||||
|
64
CHANGELOG.md
64
CHANGELOG.md
@@ -1,3 +1,67 @@
|
||||
Version 5.4.0 (2024-12-30)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Added `Property::isAbstract()` and `Property::isFinal()` methods.
|
||||
* Added `PropertyHook::isFinal()` method.
|
||||
* Emit an error if property hook is used on declaration with multiple properties.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Make legacy class aliases compatible with classmap-authoritative autoloader.
|
||||
* `Param::isPromoted()` and `Param::isPublic()` now returns true for parameters that have property
|
||||
hooks but no explicit visibility modifier.
|
||||
* `PropertyHook::getStmts()` now correctly desugars short `set` hooks. `set => $value` will be
|
||||
expanded to `set { $this->propertyName = $value; }`. This requires the `propertyName` attribute
|
||||
on the hook to be set, which is now also set by the parser. If the attribute is not set,
|
||||
`getStmts()` will throw an error for short set hooks, as it is not possible to produce a correct
|
||||
desugaring.
|
||||
|
||||
Version 5.3.1 (2024-10-08)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for declaring functions with name `exit` or `die`, to allow their use in stubs.
|
||||
|
||||
Version 5.3.0 (2024-09-29)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* Added `indent` option to pretty printer, which can be used to specify the indentation to use
|
||||
(defaulting to four spaces). This also allows using tab indentation.
|
||||
|
||||
### Fixed
|
||||
|
||||
* Resolve names in `PropertyHook`s in the `NameResolver`.
|
||||
* Include the trailing semicolon inside `Stmt\GroupUse` nodes, making them consistent with
|
||||
`Stmt\Use_` nodes.
|
||||
* Fixed indentation sometimes becoming negative in formatting-preserving pretty printer, resulting
|
||||
in `ValueError`s.
|
||||
|
||||
Version 5.2.0 (2024-09-15)
|
||||
--------------------------
|
||||
|
||||
### Added
|
||||
|
||||
* [8.4] Added support for `__PROPERTY__` magic constant, represented using a
|
||||
`Node\Scalar\MagicConst\Property` node.
|
||||
* [8.4] Added support for property hooks, which are represented using a new `hooks` subnode on
|
||||
`Node\Stmt\Property` and `Node\Param`, which contains an array of `Node\PropertyHook`.
|
||||
* [8.4] Added support for asymmetric visibility modifiers. Property `flags` can now hold the
|
||||
additional bits `Modifiers::PUBLIC_SET`, `Modifiers::PROTECTED_SET` and `Modifiers::PRIVATE_SET`.
|
||||
* [8.4] Added support for generalized exit function. For backwards compatibility, exit without
|
||||
argument or a single plain argument continues to use a `Node\Expr\Exit_` node. Otherwise (e.g.
|
||||
if a named argument is used) it will be represented as a plain `Node\Expr\FuncCall`.
|
||||
* Added support for passing enum values to various builder methods, like `BuilderFactory::val()`.
|
||||
|
||||
### Removed
|
||||
|
||||
* Removed support for alternative array syntax `$array{0}` from the PHP 8 parser. It is still
|
||||
supported by the PHP 7 parser. This is necessary in order to support property hooks.
|
||||
|
||||
Version 5.1.0 (2024-07-01)
|
||||
--------------------------
|
||||
|
||||
|
4
Makefile
4
Makefile
@@ -4,7 +4,7 @@ tools/vendor:
|
||||
composer install -d tools
|
||||
|
||||
phpstan: tools/vendor
|
||||
tools/vendor/bin/phpstan
|
||||
php tools/vendor/bin/phpstan
|
||||
|
||||
php-cs-fixer: tools/vendor
|
||||
tools/vendor/bin/php-cs-fixer fix
|
||||
php tools/vendor/bin/php-cs-fixer fix
|
||||
|
@@ -6,7 +6,7 @@ PHP Parser
|
||||
This is a PHP parser written in PHP. Its purpose is to simplify static code analysis and
|
||||
manipulation.
|
||||
|
||||
[**Documentation for version 5.x**][doc_master] (current; for running on PHP >= 7.4; for parsing PHP 7.0 to PHP 8.3, with limited support for parsing PHP 5.x).
|
||||
[**Documentation for version 5.x**][doc_master] (current; for running on PHP >= 7.4; for parsing PHP 7.0 to PHP 8.4, with limited support for parsing PHP 5.x).
|
||||
|
||||
[Documentation for version 4.x][doc_4_x] (supported; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.3).
|
||||
|
||||
|
@@ -43,7 +43,7 @@ following caveats:
|
||||
|
||||
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 tokens from newer versions is provided.
|
||||
This allows to parse PHP 8.3 source code running on PHP 7.4, for example. This emulation is not
|
||||
This allows to parse PHP 8.4 source code running on PHP 7.4, for example. This emulation is not
|
||||
perfect, but works well in practice.
|
||||
|
||||
Finally, it should be noted that the parser aims to accept all valid code, not reject all invalid
|
||||
|
@@ -104,7 +104,7 @@ This will result in the following output (which includes attributes):
|
||||
"nodeType": "Scalar_String",
|
||||
"attributes": {
|
||||
"startLine": 5,
|
||||
"endLine": 5
|
||||
"endLine": 5,
|
||||
"kind": 2,
|
||||
"rawValue": "\"\\n\""
|
||||
},
|
||||
|
@@ -37,6 +37,7 @@ integer should be printed as decimal, hexadecimal, etc). Additionally, it suppor
|
||||
* `phpVersion` (defaults to 7.4) allows opting into formatting that is not supported by older PHP
|
||||
versions.
|
||||
* `newline` (defaults to `"\n"`) can be set to `"\r\n"` in order to produce Windows newlines.
|
||||
* `indent` (defaults to four spaces `" "`) can be set to any number of spaces or a single tab.
|
||||
* `shortArraySyntax` determines the used array syntax if the `kind` attribute is not set. This is
|
||||
a legacy option, and `phpVersion` should be used to control this behavior instead.
|
||||
|
||||
|
@@ -81,7 +81,10 @@
|
||||
%token T_USE
|
||||
%token T_INSTEADOF
|
||||
%token T_GLOBAL
|
||||
%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_READONLY
|
||||
%token T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC T_READONLY
|
||||
%token T_PUBLIC_SET
|
||||
%token T_PROTECTED_SET
|
||||
%token T_PRIVATE_SET
|
||||
%token T_VAR
|
||||
%token T_UNSET
|
||||
%token T_ISSET
|
||||
@@ -103,6 +106,7 @@
|
||||
%token T_TRAIT_C
|
||||
%token T_METHOD_C
|
||||
%token T_FUNC_C
|
||||
%token T_PROPERTY_C
|
||||
%token T_LINE
|
||||
%token T_FILE
|
||||
%token T_START_HEREDOC
|
||||
@@ -252,7 +256,7 @@ top_statement:
|
||||
$this->checkNamespace($$); }
|
||||
| T_USE use_declarations semi { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; }
|
||||
| T_USE use_type use_declarations semi { $$ = Stmt\Use_[$3, $2]; }
|
||||
| group_use_declaration semi
|
||||
| group_use_declaration
|
||||
| T_CONST constant_declaration_list semi { $$ = Stmt\Const_[$2]; }
|
||||
;
|
||||
|
||||
@@ -262,9 +266,9 @@ use_type:
|
||||
;
|
||||
|
||||
group_use_declaration:
|
||||
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
|
||||
T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' semi
|
||||
{ $$ = Stmt\GroupUse[$3, $6, $2]; }
|
||||
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
|
||||
| T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' semi
|
||||
{ $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; }
|
||||
;
|
||||
|
||||
@@ -460,15 +464,16 @@ block_or_error:
|
||||
| error { $$ = []; }
|
||||
;
|
||||
|
||||
identifier_maybe_readonly:
|
||||
fn_identifier:
|
||||
identifier_not_reserved
|
||||
| T_READONLY { $$ = Node\Identifier[$1]; }
|
||||
| T_EXIT { $$ = Node\Identifier[$1]; }
|
||||
;
|
||||
|
||||
function_declaration_statement:
|
||||
T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error
|
||||
T_FUNCTION optional_ref fn_identifier '(' parameter_list ')' optional_return_type block_or_error
|
||||
{ $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; }
|
||||
| attributes T_FUNCTION optional_ref identifier_maybe_readonly '(' parameter_list ')' optional_return_type block_or_error
|
||||
| attributes T_FUNCTION optional_ref fn_identifier '(' parameter_list ')' optional_return_type block_or_error
|
||||
{ $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; }
|
||||
;
|
||||
|
||||
@@ -671,18 +676,23 @@ property_modifier:
|
||||
T_PUBLIC { $$ = Modifiers::PUBLIC; }
|
||||
| T_PROTECTED { $$ = Modifiers::PROTECTED; }
|
||||
| T_PRIVATE { $$ = Modifiers::PRIVATE; }
|
||||
| T_PUBLIC_SET { $$ = Modifiers::PUBLIC_SET; }
|
||||
| T_PROTECTED_SET { $$ = Modifiers::PROTECTED_SET; }
|
||||
| T_PRIVATE_SET { $$ = Modifiers::PRIVATE_SET; }
|
||||
| T_READONLY { $$ = Modifiers::READONLY; }
|
||||
;
|
||||
|
||||
parameter:
|
||||
optional_attributes optional_property_modifiers optional_type_without_static
|
||||
optional_arg_ref optional_ellipsis plain_variable
|
||||
{ $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1);
|
||||
$this->checkParam($$); }
|
||||
optional_arg_ref optional_ellipsis plain_variable optional_property_hook_list
|
||||
{ $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1, $7);
|
||||
$this->checkParam($$);
|
||||
$this->addPropertyNameToHooks($$); }
|
||||
| optional_attributes optional_property_modifiers optional_type_without_static
|
||||
optional_arg_ref optional_ellipsis plain_variable '=' expr
|
||||
{ $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1);
|
||||
$this->checkParam($$); }
|
||||
optional_arg_ref optional_ellipsis plain_variable '=' expr optional_property_hook_list
|
||||
{ $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1, $9);
|
||||
$this->checkParam($$);
|
||||
$this->addPropertyNameToHooks($$); }
|
||||
| optional_attributes optional_property_modifiers optional_type_without_static
|
||||
optional_arg_ref optional_ellipsis error
|
||||
{ $$ = new Node\Param(Expr\Error[], null, $3, $4, $5, attributes(), $2, $1); }
|
||||
@@ -828,8 +838,14 @@ class_statement_list:
|
||||
|
||||
class_statement:
|
||||
optional_attributes variable_modifiers optional_type_without_static property_declaration_list semi
|
||||
{ $$ = new Stmt\Property($2, $4, attributes(), $3, $1);
|
||||
$this->checkProperty($$, #2); }
|
||||
{ $$ = new Stmt\Property($2, $4, attributes(), $3, $1); }
|
||||
#if PHP8
|
||||
| optional_attributes variable_modifiers optional_type_without_static property_declaration_list '{' property_hook_list '}'
|
||||
{ $$ = new Stmt\Property($2, $4, attributes(), $3, $1, $6);
|
||||
$this->checkPropertyHooksForMultiProperty($$, #5);
|
||||
$this->checkEmptyPropertyHookList($6, #5);
|
||||
$this->addPropertyNameToHooks($$); }
|
||||
#endif
|
||||
| optional_attributes method_modifiers T_CONST class_const_list semi
|
||||
{ $$ = new Stmt\ClassConst($4, $2, attributes(), $1);
|
||||
$this->checkClassConst($$, #2); }
|
||||
@@ -901,6 +917,9 @@ member_modifier:
|
||||
T_PUBLIC { $$ = Modifiers::PUBLIC; }
|
||||
| T_PROTECTED { $$ = Modifiers::PROTECTED; }
|
||||
| T_PRIVATE { $$ = Modifiers::PRIVATE; }
|
||||
| T_PUBLIC_SET { $$ = Modifiers::PUBLIC_SET; }
|
||||
| T_PROTECTED_SET { $$ = Modifiers::PROTECTED_SET; }
|
||||
| T_PRIVATE_SET { $$ = Modifiers::PRIVATE_SET; }
|
||||
| T_STATIC { $$ = Modifiers::STATIC; }
|
||||
| T_ABSTRACT { $$ = Modifiers::ABSTRACT; }
|
||||
| T_FINAL { $$ = Modifiers::FINAL; }
|
||||
@@ -926,6 +945,39 @@ property_declaration:
|
||||
| property_decl_name '=' expr { $$ = Node\PropertyItem[$1, $3]; }
|
||||
;
|
||||
|
||||
property_hook_list:
|
||||
/* empty */ { $$ = []; }
|
||||
| property_hook_list property_hook { push($1, $2); }
|
||||
;
|
||||
|
||||
optional_property_hook_list:
|
||||
/* empty */ { $$ = []; }
|
||||
#if PHP8
|
||||
| '{' property_hook_list '}' { $$ = $2; $this->checkEmptyPropertyHookList($2, #1); }
|
||||
#endif
|
||||
;
|
||||
|
||||
property_hook:
|
||||
optional_attributes property_hook_modifiers optional_ref identifier_not_reserved property_hook_body
|
||||
{ $$ = Node\PropertyHook[$4, $5, ['flags' => $2, 'byRef' => $3, 'params' => [], 'attrGroups' => $1]];
|
||||
$this->checkPropertyHook($$, null); }
|
||||
| optional_attributes property_hook_modifiers optional_ref identifier_not_reserved '(' parameter_list ')' property_hook_body
|
||||
{ $$ = Node\PropertyHook[$4, $8, ['flags' => $2, 'byRef' => $3, 'params' => $6, 'attrGroups' => $1]];
|
||||
$this->checkPropertyHook($$, #5); }
|
||||
;
|
||||
|
||||
property_hook_body:
|
||||
';' { $$ = null; }
|
||||
| '{' inner_statement_list '}' { $$ = $2; }
|
||||
| T_DOUBLE_ARROW expr ';' { $$ = $2; }
|
||||
;
|
||||
|
||||
property_hook_modifiers:
|
||||
/* empty */ { $$ = 0; }
|
||||
| property_hook_modifiers member_modifier
|
||||
{ $this->checkPropertyHookModifiers($1, $2, #2); $$ = $1 | $2; }
|
||||
;
|
||||
|
||||
expr_list_forbid_comma:
|
||||
non_empty_expr_list no_comma
|
||||
;
|
||||
@@ -1030,10 +1082,8 @@ expr:
|
||||
| T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; }
|
||||
| T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; }
|
||||
| T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; }
|
||||
| T_EXIT exit_expr
|
||||
{ $attrs = attributes();
|
||||
$attrs['kind'] = strtolower($1) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE;
|
||||
$$ = new Expr\Exit_($2, $attrs); }
|
||||
| T_EXIT ctor_arguments
|
||||
{ $$ = $this->createExitExpr($1, #1, $2, attributes()); }
|
||||
| '@' expr { $$ = Expr\ErrorSuppress[$2]; }
|
||||
| scalar
|
||||
| '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; }
|
||||
@@ -1138,11 +1188,6 @@ class_name_or_var:
|
||||
| fully_dereferenceable
|
||||
;
|
||||
|
||||
exit_expr:
|
||||
/* empty */ { $$ = null; }
|
||||
| '(' optional_expr ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
backticks_expr:
|
||||
/* empty */ { $$ = array(); }
|
||||
| encaps_string_part
|
||||
@@ -1165,6 +1210,7 @@ constant:
|
||||
| T_METHOD_C { $$ = Scalar\MagicConst\Method[]; }
|
||||
| T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; }
|
||||
| T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; }
|
||||
| T_PROPERTY_C { $$ = Scalar\MagicConst\Property[]; }
|
||||
;
|
||||
|
||||
class_constant:
|
||||
@@ -1240,7 +1286,9 @@ callable_expr:
|
||||
callable_variable:
|
||||
simple_variable
|
||||
| array_object_dereferenceable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
#if PHP7
|
||||
| array_object_dereferenceable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
#endif
|
||||
| function_call
|
||||
| array_object_dereferenceable T_OBJECT_OPERATOR property_name argument_list
|
||||
{ $$ = Expr\MethodCall[$1, $3, $4]; }
|
||||
@@ -1282,7 +1330,9 @@ static_member:
|
||||
new_variable:
|
||||
simple_variable
|
||||
| new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
#if PHP7
|
||||
| new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; }
|
||||
#endif
|
||||
| new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; }
|
||||
| new_variable T_NULLSAFE_OBJECT_OPERATOR property_name { $$ = Expr\NullsafePropertyFetch[$1, $3]; }
|
||||
| class_name T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name
|
||||
|
@@ -28,7 +28,7 @@ class ClassConst implements PhpParser\Builder {
|
||||
* Creates a class constant builder
|
||||
*
|
||||
* @param string|Identifier $name Name
|
||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
||||
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||
*/
|
||||
public function __construct($name, $value) {
|
||||
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
|
||||
@@ -38,7 +38,7 @@ class ClassConst implements PhpParser\Builder {
|
||||
* Add another constant to const group
|
||||
*
|
||||
* @param string|Identifier $name Name
|
||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
||||
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
|
@@ -13,7 +13,6 @@ use PhpParser\Node\Stmt;
|
||||
class EnumCase implements PhpParser\Builder {
|
||||
/** @var Identifier|string */
|
||||
protected $name;
|
||||
/** @var ?Node\Expr */
|
||||
protected ?Node\Expr $value = null;
|
||||
/** @var array<string, mixed> */
|
||||
protected array $attributes = [];
|
||||
|
@@ -122,6 +122,28 @@ class Param implements PhpParser\Builder {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the promoted property private(set) visibility.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePrivateSet() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the promoted property protected(set) visibility.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeProtectedSet() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an attribute group.
|
||||
*
|
||||
|
@@ -23,6 +23,8 @@ class Property implements PhpParser\Builder {
|
||||
protected ?Node $type = null;
|
||||
/** @var list<Node\AttributeGroup> */
|
||||
protected array $attributeGroups = [];
|
||||
/** @var list<Node\PropertyHook> */
|
||||
protected array $hooks = [];
|
||||
|
||||
/**
|
||||
* Creates a property builder.
|
||||
@@ -88,6 +90,50 @@ class Property implements PhpParser\Builder {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the property abstract. Requires at least one property hook to be specified as well.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeAbstract() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the property final.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeFinal() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the property private(set) visibility.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makePrivateSet() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the property protected(set) visibility.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function makeProtectedSet() {
|
||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for the property.
|
||||
*
|
||||
@@ -142,12 +188,27 @@ class Property implements PhpParser\Builder {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a property hook.
|
||||
*
|
||||
* @return $this The builder instance (for fluid interface)
|
||||
*/
|
||||
public function addHook(Node\PropertyHook $hook) {
|
||||
$this->hooks[] = $hook;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the built class node.
|
||||
*
|
||||
* @return Stmt\Property The built property node
|
||||
*/
|
||||
public function getNode(): PhpParser\Node {
|
||||
if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) {
|
||||
throw new PhpParser\Error('Only hooked properties may be declared abstract');
|
||||
}
|
||||
|
||||
return new Stmt\Property(
|
||||
$this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,
|
||||
[
|
||||
@@ -155,7 +216,8 @@ class Property implements PhpParser\Builder {
|
||||
],
|
||||
$this->attributes,
|
||||
$this->type,
|
||||
$this->attributeGroups
|
||||
$this->attributeGroups,
|
||||
$this->hooks
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -210,7 +210,7 @@ class BuilderFactory {
|
||||
/**
|
||||
* Creates node a for a literal value.
|
||||
*
|
||||
* @param Expr|bool|null|int|float|string|array $value $value
|
||||
* @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value
|
||||
*/
|
||||
public function val($value): Expr {
|
||||
return BuilderHelpers::normalizeValue($value);
|
||||
|
@@ -6,6 +6,7 @@ use PhpParser\Node\ComplexType;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Stmt;
|
||||
@@ -214,7 +215,7 @@ final class BuilderHelpers {
|
||||
* Normalizes a value: Converts nulls, booleans, integers,
|
||||
* floats, strings and arrays into their respective nodes
|
||||
*
|
||||
* @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
|
||||
* @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize
|
||||
*
|
||||
* @return Expr The normalized value
|
||||
*/
|
||||
@@ -268,6 +269,10 @@ final class BuilderHelpers {
|
||||
return new Expr\Array_($items);
|
||||
}
|
||||
|
||||
if ($value instanceof \UnitEnum) {
|
||||
return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name));
|
||||
}
|
||||
|
||||
throw new \LogicException('Invalid value');
|
||||
}
|
||||
|
||||
|
@@ -20,9 +20,9 @@ class TokenStream {
|
||||
*
|
||||
* @param Token[] $tokens Tokens in PhpToken::tokenize() format
|
||||
*/
|
||||
public function __construct(array $tokens) {
|
||||
public function __construct(array $tokens, int $tabWidth) {
|
||||
$this->tokens = $tokens;
|
||||
$this->indentMap = $this->calcIndentMap();
|
||||
$this->indentMap = $this->calcIndentMap($tabWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,7 +248,7 @@ class TokenStream {
|
||||
*
|
||||
* @return int[] Token position to indentation map
|
||||
*/
|
||||
private function calcIndentMap(): array {
|
||||
private function calcIndentMap(int $tabWidth): array {
|
||||
$indentMap = [];
|
||||
$indent = 0;
|
||||
foreach ($this->tokens as $i => $token) {
|
||||
@@ -258,11 +258,11 @@ class TokenStream {
|
||||
$content = $token->text;
|
||||
$newlinePos = \strrpos($content, "\n");
|
||||
if (false !== $newlinePos) {
|
||||
$indent = \strlen($content) - $newlinePos - 1;
|
||||
$indent = $this->getIndent(\substr($content, $newlinePos + 1), $tabWidth);
|
||||
} elseif ($i === 1 && $this->tokens[0]->id === \T_OPEN_TAG &&
|
||||
$this->tokens[0]->text[\strlen($this->tokens[0]->text) - 1] === "\n") {
|
||||
// Special case: Newline at the end of opening tag followed by whitespace.
|
||||
$indent = \strlen($content);
|
||||
$indent = $this->getIndent($content, $tabWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,4 +272,11 @@ class TokenStream {
|
||||
|
||||
return $indentMap;
|
||||
}
|
||||
|
||||
private function getIndent(string $ws, int $tabWidth): int {
|
||||
$spaces = \substr_count($ws, " ");
|
||||
$tabs = \substr_count($ws, "\t");
|
||||
assert(\strlen($ws) === $spaces + $tabs);
|
||||
return $spaces + $tabs * $tabWidth;
|
||||
}
|
||||
}
|
||||
|
@@ -5,15 +5,13 @@ namespace PhpParser\Lexer;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\ErrorHandler;
|
||||
use PhpParser\Lexer;
|
||||
use PhpParser\Lexer\TokenEmulator\AsymmetricVisibilityTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\AttributeEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\EnumTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\CoaleseEqualTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\ExplicitOctalEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\FlexibleDocStringEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\FnTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\NumericLiteralSeparatorEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\PropertyTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\ReadonlyFunctionTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator;
|
||||
use PhpParser\Lexer\TokenEmulator\ReverseEmulator;
|
||||
@@ -47,6 +45,8 @@ class Emulative extends Lexer {
|
||||
new ReadonlyTokenEmulator(),
|
||||
new ExplicitOctalEmulator(),
|
||||
new ReadonlyFunctionTokenEmulator(),
|
||||
new PropertyTokenEmulator(),
|
||||
new AsymmetricVisibilityTokenEmulator(),
|
||||
];
|
||||
|
||||
// Collect emulators that are relevant for the PHP version we're running
|
||||
|
@@ -0,0 +1,93 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\PhpVersion;
|
||||
use PhpParser\Token;
|
||||
|
||||
final class AsymmetricVisibilityTokenEmulator extends TokenEmulator {
|
||||
public function getPhpVersion(): PhpVersion {
|
||||
return PhpVersion::fromComponents(8, 4);
|
||||
}
|
||||
public function isEmulationNeeded(string $code): bool {
|
||||
$code = strtolower($code);
|
||||
return strpos($code, 'public(set)') !== false ||
|
||||
strpos($code, 'protected(set)') !== false ||
|
||||
strpos($code, 'private(set)') !== false;
|
||||
}
|
||||
|
||||
public function emulate(string $code, array $tokens): array {
|
||||
$map = [
|
||||
\T_PUBLIC => \T_PUBLIC_SET,
|
||||
\T_PROTECTED => \T_PROTECTED_SET,
|
||||
\T_PRIVATE => \T_PRIVATE_SET,
|
||||
];
|
||||
for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
|
||||
$token = $tokens[$i];
|
||||
if (isset($map[$token->id]) && $i + 3 < $c && $tokens[$i + 1]->text === '(' &&
|
||||
$tokens[$i + 2]->id === \T_STRING && \strtolower($tokens[$i + 2]->text) === 'set' &&
|
||||
$tokens[$i + 3]->text === ')' &&
|
||||
$this->isKeywordContext($tokens, $i)
|
||||
) {
|
||||
array_splice($tokens, $i, 4, [
|
||||
new Token(
|
||||
$map[$token->id], $token->text . '(' . $tokens[$i + 2]->text . ')',
|
||||
$token->line, $token->pos),
|
||||
]);
|
||||
$c -= 3;
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function reverseEmulate(string $code, array $tokens): array {
|
||||
$reverseMap = [
|
||||
\T_PUBLIC_SET => \T_PUBLIC,
|
||||
\T_PROTECTED_SET => \T_PROTECTED,
|
||||
\T_PRIVATE_SET => \T_PRIVATE,
|
||||
];
|
||||
for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
|
||||
$token = $tokens[$i];
|
||||
if (isset($reverseMap[$token->id]) &&
|
||||
\preg_match('/(public|protected|private)\((set)\)/i', $token->text, $matches)
|
||||
) {
|
||||
[, $modifier, $set] = $matches;
|
||||
$modifierLen = \strlen($modifier);
|
||||
array_splice($tokens, $i, 1, [
|
||||
new Token($reverseMap[$token->id], $modifier, $token->line, $token->pos),
|
||||
new Token(\ord('('), '(', $token->line, $token->pos + $modifierLen),
|
||||
new Token(\T_STRING, $set, $token->line, $token->pos + $modifierLen + 1),
|
||||
new Token(\ord(')'), ')', $token->line, $token->pos + $modifierLen + 4),
|
||||
]);
|
||||
$i += 3;
|
||||
$c += 3;
|
||||
}
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/** @param Token[] $tokens */
|
||||
protected function isKeywordContext(array $tokens, int $pos): bool {
|
||||
$prevToken = $this->getPreviousNonSpaceToken($tokens, $pos);
|
||||
if ($prevToken === null) {
|
||||
return false;
|
||||
}
|
||||
return $prevToken->id !== \T_OBJECT_OPERATOR
|
||||
&& $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR;
|
||||
}
|
||||
|
||||
/** @param Token[] $tokens */
|
||||
private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token {
|
||||
for ($i = $start - 1; $i >= 0; --$i) {
|
||||
if ($tokens[$i]->id === T_WHITESPACE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $tokens[$i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -14,8 +14,12 @@ abstract class KeywordEmulator extends TokenEmulator {
|
||||
|
||||
/** @param Token[] $tokens */
|
||||
protected function isKeywordContext(array $tokens, int $pos): bool {
|
||||
$previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos);
|
||||
return $previousNonSpaceToken === null || $previousNonSpaceToken->id !== \T_OBJECT_OPERATOR;
|
||||
$prevToken = $this->getPreviousNonSpaceToken($tokens, $pos);
|
||||
if ($prevToken === null) {
|
||||
return false;
|
||||
}
|
||||
return $prevToken->id !== \T_OBJECT_OPERATOR
|
||||
&& $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR;
|
||||
}
|
||||
|
||||
public function emulate(string $code, array $tokens): array {
|
||||
|
19
lib/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php
Normal file
19
lib/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Lexer\TokenEmulator;
|
||||
|
||||
use PhpParser\PhpVersion;
|
||||
|
||||
final class PropertyTokenEmulator extends KeywordEmulator {
|
||||
public function getPhpVersion(): PhpVersion {
|
||||
return PhpVersion::fromComponents(8, 4);
|
||||
}
|
||||
|
||||
public function getKeywordString(): string {
|
||||
return '__property__';
|
||||
}
|
||||
|
||||
public function getKeywordToken(): int {
|
||||
return \T_PROPERTY_C;
|
||||
}
|
||||
}
|
@@ -14,23 +14,47 @@ final class Modifiers {
|
||||
public const ABSTRACT = 16;
|
||||
public const FINAL = 32;
|
||||
public const READONLY = 64;
|
||||
public const PUBLIC_SET = 128;
|
||||
public const PROTECTED_SET = 256;
|
||||
public const PRIVATE_SET = 512;
|
||||
|
||||
public const VISIBILITY_MASK = 1 | 2 | 4;
|
||||
public const VISIBILITY_MASK = self::PUBLIC | self::PROTECTED | self::PRIVATE;
|
||||
|
||||
public const VISIBILITY_SET_MASK = self::PUBLIC_SET | self::PROTECTED_SET | self::PRIVATE_SET;
|
||||
|
||||
private const TO_STRING_MAP = [
|
||||
self::PUBLIC => 'public',
|
||||
self::PROTECTED => 'protected',
|
||||
self::PRIVATE => 'private',
|
||||
self::STATIC => 'static',
|
||||
self::ABSTRACT => 'abstract',
|
||||
self::FINAL => 'final',
|
||||
self::READONLY => 'readonly',
|
||||
self::PUBLIC_SET => 'public(set)',
|
||||
self::PROTECTED_SET => 'protected(set)',
|
||||
self::PRIVATE_SET => 'private(set)',
|
||||
];
|
||||
|
||||
public static function toString(int $modifier): string {
|
||||
if (!isset(self::TO_STRING_MAP[$modifier])) {
|
||||
throw new \InvalidArgumentException("Unknown modifier $modifier");
|
||||
}
|
||||
return self::TO_STRING_MAP[$modifier];
|
||||
}
|
||||
|
||||
private static function isValidModifier(int $modifier): bool {
|
||||
$isPow2 = ($modifier & ($modifier - 1)) == 0 && $modifier != 0;
|
||||
return $isPow2 && $modifier <= self::PRIVATE_SET;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function verifyClassModifier(int $a, int $b): void {
|
||||
if ($a & Modifiers::ABSTRACT && $b & Modifiers::ABSTRACT) {
|
||||
throw new Error('Multiple abstract modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::FINAL && $b & Modifiers::FINAL) {
|
||||
throw new Error('Multiple final modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::READONLY && $b & Modifiers::READONLY) {
|
||||
throw new Error('Multiple readonly modifiers are not allowed');
|
||||
assert(self::isValidModifier($b));
|
||||
if (($a & $b) != 0) {
|
||||
throw new Error(
|
||||
'Multiple ' . self::toString($b) . ' modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & 48 && $b & 48) {
|
||||
@@ -42,24 +66,16 @@ final class Modifiers {
|
||||
* @internal
|
||||
*/
|
||||
public static function verifyModifier(int $a, int $b): void {
|
||||
if ($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK) {
|
||||
assert(self::isValidModifier($b));
|
||||
if (($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK) ||
|
||||
($a & Modifiers::VISIBILITY_SET_MASK && $b & Modifiers::VISIBILITY_SET_MASK)
|
||||
) {
|
||||
throw new Error('Multiple access type modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::ABSTRACT && $b & Modifiers::ABSTRACT) {
|
||||
throw new Error('Multiple abstract modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::STATIC && $b & Modifiers::STATIC) {
|
||||
throw new Error('Multiple static modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::FINAL && $b & Modifiers::FINAL) {
|
||||
throw new Error('Multiple final modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & Modifiers::READONLY && $b & Modifiers::READONLY) {
|
||||
throw new Error('Multiple readonly modifiers are not allowed');
|
||||
if (($a & $b) != 0) {
|
||||
throw new Error(
|
||||
'Multiple ' . self::toString($b) . ' modifiers are not allowed');
|
||||
}
|
||||
|
||||
if ($a & 48 && $b & 48) {
|
||||
|
@@ -185,7 +185,7 @@ class NameContext {
|
||||
// Check for relevant type-specific use statements
|
||||
foreach ($this->origAliases[$type] as $alias => $orig) {
|
||||
if ($type === Stmt\Use_::TYPE_CONSTANT) {
|
||||
// Constants are are complicated-sensitive
|
||||
// Constants are complicated-sensitive
|
||||
$normalizedOrig = $this->normalizeConstName($orig->toString());
|
||||
if ($normalizedOrig === $this->normalizeConstName($name)) {
|
||||
$possibleNames[] = new Name($alias);
|
||||
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
require __DIR__ . '/../ArrayItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class ArrayItem extends \PhpParser\Node\ArrayItem {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
require __DIR__ . '/../ClosureUse.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class ClosureUse extends \PhpParser\Node\ClosureUse {
|
||||
}
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ class Identifier extends NodeAbstract {
|
||||
/**
|
||||
* Get lowercased identifier as string.
|
||||
*
|
||||
* @psalm-return non-empty-string
|
||||
* @psalm-return non-empty-string&lowercase-string
|
||||
* @return string Lowercased identifier as string
|
||||
*/
|
||||
public function toLowerString(): string {
|
||||
|
@@ -129,7 +129,7 @@ class Name extends NodeAbstract {
|
||||
* Returns lowercased string representation of the name, without taking the name type into
|
||||
* account (e.g., no leading backslash for fully qualified names).
|
||||
*
|
||||
* @psalm-return non-empty-string
|
||||
* @psalm-return non-empty-string&lowercase-string
|
||||
* @return string Lowercased string representation
|
||||
*/
|
||||
public function toLowerString(): string {
|
||||
|
@@ -21,6 +21,8 @@ class Param extends NodeAbstract {
|
||||
public int $flags;
|
||||
/** @var AttributeGroup[] PHP attribute groups */
|
||||
public array $attrGroups;
|
||||
/** @var PropertyHook[] Property hooks for promoted properties */
|
||||
public array $hooks;
|
||||
|
||||
/**
|
||||
* Constructs a parameter node.
|
||||
@@ -33,13 +35,15 @@ class Param extends NodeAbstract {
|
||||
* @param array<string, mixed> $attributes Additional attributes
|
||||
* @param int $flags Optional visibility flags
|
||||
* @param list<AttributeGroup> $attrGroups PHP attribute groups
|
||||
* @param PropertyHook[] $hooks Property hooks for promoted properties
|
||||
*/
|
||||
public function __construct(
|
||||
Expr $var, ?Expr $default = null, ?Node $type = null,
|
||||
bool $byRef = false, bool $variadic = false,
|
||||
array $attributes = [],
|
||||
int $flags = 0,
|
||||
array $attrGroups = []
|
||||
array $attrGroups = [],
|
||||
array $hooks = []
|
||||
) {
|
||||
$this->attributes = $attributes;
|
||||
$this->type = $type;
|
||||
@@ -49,10 +53,11 @@ class Param extends NodeAbstract {
|
||||
$this->default = $default;
|
||||
$this->flags = $flags;
|
||||
$this->attrGroups = $attrGroups;
|
||||
$this->hooks = $hooks;
|
||||
}
|
||||
|
||||
public function getSubNodeNames(): array {
|
||||
return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default'];
|
||||
return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default', 'hooks'];
|
||||
}
|
||||
|
||||
public function getType(): string {
|
||||
@@ -63,11 +68,20 @@ class Param extends NodeAbstract {
|
||||
* Whether this parameter uses constructor property promotion.
|
||||
*/
|
||||
public function isPromoted(): bool {
|
||||
return $this->flags !== 0;
|
||||
return $this->flags !== 0 || $this->hooks !== [];
|
||||
}
|
||||
|
||||
public function isPublic(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PUBLIC);
|
||||
$public = (bool) ($this->flags & Modifiers::PUBLIC);
|
||||
if ($public) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hooks === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ($this->flags & Modifiers::VISIBILITY_MASK) === 0;
|
||||
}
|
||||
|
||||
public function isProtected(): bool {
|
||||
@@ -81,4 +95,25 @@ class Param extends NodeAbstract {
|
||||
public function isReadonly(): bool {
|
||||
return (bool) ($this->flags & Modifiers::READONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the promoted property has explicit public(set) visibility.
|
||||
*/
|
||||
public function isPublicSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PUBLIC_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the promoted property has explicit protected(set) visibility.
|
||||
*/
|
||||
public function isProtectedSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PROTECTED_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the promoted property has explicit private(set) visibility.
|
||||
*/
|
||||
public function isPrivateSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PRIVATE_SET);
|
||||
}
|
||||
}
|
||||
|
105
lib/PhpParser/Node/PropertyHook.php
Normal file
105
lib/PhpParser/Node/PropertyHook.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Modifiers;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\NodeAbstract;
|
||||
|
||||
class PropertyHook extends NodeAbstract implements FunctionLike {
|
||||
/** @var AttributeGroup[] PHP attribute groups */
|
||||
public array $attrGroups;
|
||||
/** @var int Modifiers */
|
||||
public int $flags;
|
||||
/** @var bool Whether hook returns by reference */
|
||||
public bool $byRef;
|
||||
/** @var Identifier Hook name */
|
||||
public Identifier $name;
|
||||
/** @var Param[] Parameters */
|
||||
public array $params;
|
||||
/** @var null|Expr|Stmt[] Hook body */
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Constructs a property hook node.
|
||||
*
|
||||
* @param string|Identifier $name Hook name
|
||||
* @param null|Expr|Stmt[] $body Hook body
|
||||
* @param array{
|
||||
* flags?: int,
|
||||
* byRef?: bool,
|
||||
* params?: Param[],
|
||||
* attrGroups?: AttributeGroup[],
|
||||
* } $subNodes Array of the following optional subnodes:
|
||||
* 'flags => 0 : Flags
|
||||
* 'byRef' => false : Whether hook returns by reference
|
||||
* 'params' => array(): Parameters
|
||||
* 'attrGroups' => array(): PHP attribute groups
|
||||
* @param array<string, mixed> $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, $body, array $subNodes = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->name = \is_string($name) ? new Identifier($name) : $name;
|
||||
$this->body = $body;
|
||||
$this->flags = $subNodes['flags'] ?? 0;
|
||||
$this->byRef = $subNodes['byRef'] ?? false;
|
||||
$this->params = $subNodes['params'] ?? [];
|
||||
$this->attrGroups = $subNodes['attrGroups'] ?? [];
|
||||
}
|
||||
|
||||
public function returnsByRef(): bool {
|
||||
return $this->byRef;
|
||||
}
|
||||
|
||||
public function getParams(): array {
|
||||
return $this->params;
|
||||
}
|
||||
|
||||
public function getReturnType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property hook is final.
|
||||
*/
|
||||
public function isFinal(): bool {
|
||||
return (bool) ($this->flags & Modifiers::FINAL);
|
||||
}
|
||||
|
||||
public function getStmts(): ?array {
|
||||
if ($this->body instanceof Expr) {
|
||||
$name = $this->name->toLowerString();
|
||||
if ($name === 'get') {
|
||||
return [new Return_($this->body)];
|
||||
}
|
||||
if ($name === 'set') {
|
||||
if (!$this->hasAttribute('propertyName')) {
|
||||
throw new \LogicException(
|
||||
'Can only use getStmts() on a "set" hook if the "propertyName" attribute is set');
|
||||
}
|
||||
|
||||
$propName = $this->getAttribute('propertyName');
|
||||
$prop = new PropertyFetch(new Variable('this'), (string) $propName);
|
||||
return [new Expression(new Assign($prop, $this->body))];
|
||||
}
|
||||
throw new \LogicException('Unknown property hook "' . $name . '"');
|
||||
}
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
public function getAttrGroups(): array {
|
||||
return $this->attrGroups;
|
||||
}
|
||||
|
||||
public function getType(): string {
|
||||
return 'PropertyHook';
|
||||
}
|
||||
|
||||
public function getSubNodeNames(): array {
|
||||
return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'body'];
|
||||
}
|
||||
}
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Scalar;
|
||||
|
||||
require __DIR__ . '/Float_.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class DNumber extends Float_ {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Scalar;
|
||||
|
||||
require __DIR__ . '/InterpolatedString.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class Encapsed extends InterpolatedString {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Scalar;
|
||||
|
||||
use PhpParser\Node\InterpolatedStringPart;
|
||||
|
||||
require __DIR__ . '/../InterpolatedStringPart.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class EncapsedStringPart extends InterpolatedStringPart {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Scalar;
|
||||
|
||||
require __DIR__ . '/Int_.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class LNumber extends Int_ {
|
||||
}
|
||||
}
|
||||
|
15
lib/PhpParser/Node/Scalar/MagicConst/Property.php
Normal file
15
lib/PhpParser/Node/Scalar/MagicConst/Property.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Scalar\MagicConst;
|
||||
|
||||
use PhpParser\Node\Scalar\MagicConst;
|
||||
|
||||
class Property extends MagicConst {
|
||||
public function getName(): string {
|
||||
return '__PROPERTY__';
|
||||
}
|
||||
|
||||
public function getType(): string {
|
||||
return 'Scalar_MagicConst_Property';
|
||||
}
|
||||
}
|
@@ -1,3 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node\DeclareItem;
|
||||
|
||||
require __DIR__ . '/../DeclareItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class DeclareDeclare extends DeclareItem {
|
||||
}
|
||||
}
|
||||
|
@@ -18,6 +18,8 @@ class Property extends Node\Stmt {
|
||||
public ?Node $type;
|
||||
/** @var Node\AttributeGroup[] PHP attribute groups */
|
||||
public array $attrGroups;
|
||||
/** @var Node\PropertyHook[] Property hooks */
|
||||
public array $hooks;
|
||||
|
||||
/**
|
||||
* Constructs a class property list node.
|
||||
@@ -27,17 +29,19 @@ class Property extends Node\Stmt {
|
||||
* @param array<string, mixed> $attributes Additional attributes
|
||||
* @param null|Identifier|Name|ComplexType $type Type declaration
|
||||
* @param Node\AttributeGroup[] $attrGroups PHP attribute groups
|
||||
* @param Node\PropertyHook[] $hooks Property hooks
|
||||
*/
|
||||
public function __construct(int $flags, array $props, array $attributes = [], ?Node $type = null, array $attrGroups = []) {
|
||||
public function __construct(int $flags, array $props, array $attributes = [], ?Node $type = null, array $attrGroups = [], array $hooks = []) {
|
||||
$this->attributes = $attributes;
|
||||
$this->flags = $flags;
|
||||
$this->props = $props;
|
||||
$this->type = $type;
|
||||
$this->attrGroups = $attrGroups;
|
||||
$this->hooks = $hooks;
|
||||
}
|
||||
|
||||
public function getSubNodeNames(): array {
|
||||
return ['attrGroups', 'flags', 'type', 'props'];
|
||||
return ['attrGroups', 'flags', 'type', 'props', 'hooks'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,6 +80,41 @@ class Property extends Node\Stmt {
|
||||
return (bool) ($this->flags & Modifiers::READONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property is abstract.
|
||||
*/
|
||||
public function isAbstract(): bool {
|
||||
return (bool) ($this->flags & Modifiers::ABSTRACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property is final.
|
||||
*/
|
||||
public function isFinal(): bool {
|
||||
return (bool) ($this->flags & Modifiers::FINAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property has explicit public(set) visibility.
|
||||
*/
|
||||
public function isPublicSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PUBLIC_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property has explicit protected(set) visibility.
|
||||
*/
|
||||
public function isProtectedSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PROTECTED_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the property has explicit private(set) visibility.
|
||||
*/
|
||||
public function isPrivateSet(): bool {
|
||||
return (bool) ($this->flags & Modifiers::PRIVATE_SET);
|
||||
}
|
||||
|
||||
public function getType(): string {
|
||||
return 'Stmt_Property';
|
||||
}
|
||||
|
@@ -1,3 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node\PropertyItem;
|
||||
|
||||
require __DIR__ . '/../PropertyItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class PropertyProperty extends PropertyItem {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
require __DIR__ . '/../StaticVar.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class StaticVar extends \PhpParser\Node\StaticVar {
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node\UseItem;
|
||||
|
||||
require __DIR__ . '/../UseItem.php';
|
||||
|
||||
if (false) {
|
||||
// For classmap-authoritative support.
|
||||
class UseUse extends UseItem {
|
||||
}
|
||||
}
|
||||
|
@@ -185,6 +185,15 @@ class NodeDumper {
|
||||
if ($flags & Modifiers::READONLY) {
|
||||
$strs[] = 'READONLY';
|
||||
}
|
||||
if ($flags & Modifiers::PUBLIC_SET) {
|
||||
$strs[] = 'PUBLIC_SET';
|
||||
}
|
||||
if ($flags & Modifiers::PROTECTED_SET) {
|
||||
$strs[] = 'PROTECTED_SET';
|
||||
}
|
||||
if ($flags & Modifiers::PRIVATE_SET) {
|
||||
$strs[] = 'PRIVATE_SET';
|
||||
}
|
||||
|
||||
if ($strs) {
|
||||
return implode(' | ', $strs) . ' (' . $flags . ')';
|
||||
|
@@ -99,66 +99,72 @@ class NodeTraverser implements NodeTraverserInterface {
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
} elseif ($subNode instanceof Node) {
|
||||
$traverseChildren = true;
|
||||
$visitorIndex = -1;
|
||||
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($subNode);
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $node->$name = $return;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
$node->$name = null;
|
||||
continue 2;
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'enterNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($traverseChildren) {
|
||||
$this->traverseNode($subNode);
|
||||
if ($this->stopTraversal) {
|
||||
if (!$subNode instanceof Node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$traverseChildren = true;
|
||||
$visitorIndex = -1;
|
||||
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($subNode);
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $node->$name = $return;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
$node->$name = null;
|
||||
continue 2;
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'enterNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; $visitorIndex >= 0; --$visitorIndex) {
|
||||
$visitor = $this->visitors[$visitorIndex];
|
||||
$return = $visitor->leaveNode($subNode);
|
||||
if ($traverseChildren) {
|
||||
$this->traverseNode($subNode);
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $node->$name = $return;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
$node->$name = null;
|
||||
break;
|
||||
} elseif (\is_array($return)) {
|
||||
throw new \LogicException(
|
||||
'leaveNode() may only return an array ' .
|
||||
'if the parent structure is an array'
|
||||
);
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'leaveNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
for (; $visitorIndex >= 0; --$visitorIndex) {
|
||||
$visitor = $this->visitors[$visitorIndex];
|
||||
$return = $visitor->leaveNode($subNode);
|
||||
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($subNode, $return);
|
||||
$subNode = $node->$name = $return;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
$node->$name = null;
|
||||
break;
|
||||
} elseif (\is_array($return)) {
|
||||
throw new \LogicException(
|
||||
'leaveNode() may only return an array ' .
|
||||
'if the parent structure is an array'
|
||||
);
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'leaveNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,77 +182,80 @@ class NodeTraverser implements NodeTraverserInterface {
|
||||
$doNodes = [];
|
||||
|
||||
foreach ($nodes as $i => $node) {
|
||||
if ($node instanceof Node) {
|
||||
$traverseChildren = true;
|
||||
$visitorIndex = -1;
|
||||
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($node);
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$nodes[$i] = $node = $return;
|
||||
} elseif (\is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
continue 2;
|
||||
} elseif (NodeVisitor::REMOVE_NODE === $return) {
|
||||
$doNodes[] = [$i, []];
|
||||
continue 2;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
throw new \LogicException(
|
||||
'REPLACE_WITH_NULL can not be used if the parent structure is an array');
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'enterNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!$node instanceof Node) {
|
||||
if (\is_array($node)) {
|
||||
throw new \LogicException('Invalid node structure: Contains nested arrays');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($traverseChildren) {
|
||||
$this->traverseNode($node);
|
||||
if ($this->stopTraversal) {
|
||||
$traverseChildren = true;
|
||||
$visitorIndex = -1;
|
||||
|
||||
foreach ($this->visitors as $visitorIndex => $visitor) {
|
||||
$return = $visitor->enterNode($node);
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$nodes[$i] = $node = $return;
|
||||
} elseif (\is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
continue 2;
|
||||
} elseif (NodeVisitor::REMOVE_NODE === $return) {
|
||||
$doNodes[] = [$i, []];
|
||||
continue 2;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
} elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
|
||||
$traverseChildren = false;
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
throw new \LogicException(
|
||||
'REPLACE_WITH_NULL can not be used if the parent structure is an array');
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'enterNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; $visitorIndex >= 0; --$visitorIndex) {
|
||||
$visitor = $this->visitors[$visitorIndex];
|
||||
$return = $visitor->leaveNode($node);
|
||||
if ($traverseChildren) {
|
||||
$this->traverseNode($node);
|
||||
if ($this->stopTraversal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$nodes[$i] = $node = $return;
|
||||
} elseif (\is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
break;
|
||||
} elseif (NodeVisitor::REMOVE_NODE === $return) {
|
||||
$doNodes[] = [$i, []];
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
throw new \LogicException(
|
||||
'REPLACE_WITH_NULL can not be used if the parent structure is an array');
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'leaveNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
for (; $visitorIndex >= 0; --$visitorIndex) {
|
||||
$visitor = $this->visitors[$visitorIndex];
|
||||
$return = $visitor->leaveNode($node);
|
||||
|
||||
if (null !== $return) {
|
||||
if ($return instanceof Node) {
|
||||
$this->ensureReplacementReasonable($node, $return);
|
||||
$nodes[$i] = $node = $return;
|
||||
} elseif (\is_array($return)) {
|
||||
$doNodes[] = [$i, $return];
|
||||
break;
|
||||
} elseif (NodeVisitor::REMOVE_NODE === $return) {
|
||||
$doNodes[] = [$i, []];
|
||||
break;
|
||||
} elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
|
||||
$this->stopTraversal = true;
|
||||
break 2;
|
||||
} elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
|
||||
throw new \LogicException(
|
||||
'REPLACE_WITH_NULL can not be used if the parent structure is an array');
|
||||
} else {
|
||||
throw new \LogicException(
|
||||
'leaveNode() returned invalid value of type ' . gettype($return)
|
||||
);
|
||||
}
|
||||
}
|
||||
} elseif (\is_array($node)) {
|
||||
throw new \LogicException('Invalid node structure: Contains nested arrays');
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -110,6 +110,12 @@ class NameResolver extends NodeVisitorAbstract {
|
||||
$node->type = $this->resolveType($node->type);
|
||||
}
|
||||
$this->resolveAttrGroups($node);
|
||||
} elseif ($node instanceof Node\PropertyHook) {
|
||||
foreach ($node->params as $param) {
|
||||
$param->type = $this->resolveType($param->type);
|
||||
$this->resolveAttrGroups($param);
|
||||
}
|
||||
$this->resolveAttrGroups($node);
|
||||
} elseif ($node instanceof Stmt\Const_) {
|
||||
foreach ($node->consts as $const) {
|
||||
$this->addNamespacedName($const);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ namespace PhpParser;
|
||||
* turn is based on work by Masato Bito.
|
||||
*/
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\Cast\Double;
|
||||
@@ -14,6 +15,7 @@ use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\InterpolatedStringPart;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\PropertyHook;
|
||||
use PhpParser\Node\Scalar\InterpolatedString;
|
||||
use PhpParser\Node\Scalar\Int_;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
@@ -30,6 +32,7 @@ use PhpParser\Node\Stmt\Nop;
|
||||
use PhpParser\Node\Stmt\Property;
|
||||
use PhpParser\Node\Stmt\TryCatch;
|
||||
use PhpParser\Node\UseItem;
|
||||
use PhpParser\Node\VarLikeIdentifier;
|
||||
use PhpParser\NodeVisitor\CommentAnnotatingVisitor;
|
||||
|
||||
abstract class ParserAbstract implements Parser {
|
||||
@@ -409,8 +412,6 @@ abstract class ParserAbstract implements Parser {
|
||||
$rule = $state - $this->numNonLeafStates;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Reached end of parser loop');
|
||||
}
|
||||
|
||||
protected function emitError(Error $error): void {
|
||||
@@ -1137,32 +1138,12 @@ abstract class ParserAbstract implements Parser {
|
||||
}
|
||||
|
||||
protected function checkClassConst(ClassConst $node, int $modifierPos): void {
|
||||
if ($node->flags & Modifiers::STATIC) {
|
||||
$this->emitError(new Error(
|
||||
"Cannot use 'static' as constant modifier",
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
if ($node->flags & Modifiers::ABSTRACT) {
|
||||
$this->emitError(new Error(
|
||||
"Cannot use 'abstract' as constant modifier",
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
if ($node->flags & Modifiers::READONLY) {
|
||||
$this->emitError(new Error(
|
||||
"Cannot use 'readonly' as constant modifier",
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkProperty(Property $node, int $modifierPos): void {
|
||||
if ($node->flags & Modifiers::ABSTRACT) {
|
||||
$this->emitError(new Error('Properties cannot be declared abstract',
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
|
||||
if ($node->flags & Modifiers::FINAL) {
|
||||
$this->emitError(new Error('Properties cannot be declared final',
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
foreach ([Modifiers::STATIC, Modifiers::ABSTRACT, Modifiers::READONLY] as $modifier) {
|
||||
if ($node->flags & $modifier) {
|
||||
$this->emitError(new Error(
|
||||
"Cannot use '" . Modifiers::toString($modifier) . "' as constant modifier",
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1178,6 +1159,89 @@ abstract class ParserAbstract implements Parser {
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPropertyHooksForMultiProperty(Property $property, int $hookPos): void {
|
||||
if (count($property->props) > 1) {
|
||||
$this->emitError(new Error(
|
||||
'Cannot use hooks when declaring multiple properties', $this->getAttributesAt($hookPos)));
|
||||
}
|
||||
}
|
||||
|
||||
/** @param PropertyHook[] $hooks */
|
||||
protected function checkEmptyPropertyHookList(array $hooks, int $hookPos): void {
|
||||
if (empty($hooks)) {
|
||||
$this->emitError(new Error(
|
||||
'Property hook list cannot be empty', $this->getAttributesAt($hookPos)));
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPropertyHook(PropertyHook $hook, ?int $paramListPos): void {
|
||||
$name = $hook->name->toLowerString();
|
||||
if ($name !== 'get' && $name !== 'set') {
|
||||
$this->emitError(new Error(
|
||||
'Unknown hook "' . $hook->name . '", expected "get" or "set"',
|
||||
$hook->name->getAttributes()));
|
||||
}
|
||||
if ($name === 'get' && $paramListPos !== null) {
|
||||
$this->emitError(new Error(
|
||||
'get hook must not have a parameter list', $this->getAttributesAt($paramListPos)));
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkPropertyHookModifiers(int $a, int $b, int $modifierPos): void {
|
||||
try {
|
||||
Modifiers::verifyModifier($a, $b);
|
||||
} catch (Error $error) {
|
||||
$error->setAttributes($this->getAttributesAt($modifierPos));
|
||||
$this->emitError($error);
|
||||
}
|
||||
|
||||
if ($b != Modifiers::FINAL) {
|
||||
$this->emitError(new Error(
|
||||
'Cannot use the ' . Modifiers::toString($b) . ' modifier on a property hook',
|
||||
$this->getAttributesAt($modifierPos)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Property|Param $node
|
||||
*/
|
||||
protected function addPropertyNameToHooks(Node $node): void {
|
||||
if ($node instanceof Property) {
|
||||
$name = $node->props[0]->name->toString();
|
||||
} else {
|
||||
$name = $node->var->name;
|
||||
}
|
||||
foreach ($node->hooks as $hook) {
|
||||
$hook->setAttribute('propertyName', $name);
|
||||
}
|
||||
}
|
||||
|
||||
/** @param array<Node\Arg|Node\VariadicPlaceholder> $args */
|
||||
private function isSimpleExit(array $args): bool {
|
||||
if (\count($args) === 0) {
|
||||
return true;
|
||||
}
|
||||
if (\count($args) === 1) {
|
||||
$arg = $args[0];
|
||||
return $arg instanceof Arg && $arg->name === null &&
|
||||
$arg->byRef === false && $arg->unpack === false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Node\Arg|Node\VariadicPlaceholder> $args
|
||||
* @param array<string, mixed> $attrs
|
||||
*/
|
||||
protected function createExitExpr(string $name, int $namePos, array $args, array $attrs): Expr {
|
||||
if ($this->isSimpleExit($args)) {
|
||||
// Create Exit node for backwards compatibility.
|
||||
$attrs['kind'] = strtolower($name) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE;
|
||||
return new Expr\Exit_(\count($args) === 1 ? $args[0]->value : null, $attrs);
|
||||
}
|
||||
return new Expr\FuncCall(new Name($name, $this->getAttributesAt($namePos)), $args, $attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the token map.
|
||||
*
|
||||
@@ -1190,42 +1254,23 @@ abstract class ParserAbstract implements Parser {
|
||||
protected function createTokenMap(): array {
|
||||
$tokenMap = [];
|
||||
|
||||
for ($i = 0; $i < 1000; ++$i) {
|
||||
if ($i < 256) {
|
||||
// Single-char tokens use an identity mapping.
|
||||
$tokenMap[$i] = $i;
|
||||
} elseif (\T_DOUBLE_COLON === $i) {
|
||||
// T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM
|
||||
$tokenMap[$i] = static::T_PAAMAYIM_NEKUDOTAYIM;
|
||||
} elseif (\T_OPEN_TAG_WITH_ECHO === $i) {
|
||||
// T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
|
||||
$tokenMap[$i] = static::T_ECHO;
|
||||
} elseif (\T_CLOSE_TAG === $i) {
|
||||
// T_CLOSE_TAG is equivalent to ';'
|
||||
$tokenMap[$i] = ord(';');
|
||||
} elseif ('UNKNOWN' !== $name = token_name($i)) {
|
||||
if (defined($name = static::class . '::' . $name)) {
|
||||
// Other tokens can be mapped directly
|
||||
$tokenMap[$i] = constant($name);
|
||||
}
|
||||
// Single-char tokens use an identity mapping.
|
||||
for ($i = 0; $i < 256; ++$i) {
|
||||
$tokenMap[$i] = $i;
|
||||
}
|
||||
|
||||
foreach ($this->symbolToName as $name) {
|
||||
if ($name[0] === 'T') {
|
||||
$tokenMap[\constant($name)] = constant(static::class . '::' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign tokens for which we define compatibility constants, as token_name() does not know them.
|
||||
$tokenMap[\T_FN] = static::T_FN;
|
||||
$tokenMap[\T_COALESCE_EQUAL] = static::T_COALESCE_EQUAL;
|
||||
$tokenMap[\T_NAME_QUALIFIED] = static::T_NAME_QUALIFIED;
|
||||
$tokenMap[\T_NAME_FULLY_QUALIFIED] = static::T_NAME_FULLY_QUALIFIED;
|
||||
$tokenMap[\T_NAME_RELATIVE] = static::T_NAME_RELATIVE;
|
||||
$tokenMap[\T_MATCH] = static::T_MATCH;
|
||||
$tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = static::T_NULLSAFE_OBJECT_OPERATOR;
|
||||
$tokenMap[\T_ATTRIBUTE] = static::T_ATTRIBUTE;
|
||||
$tokenMap[\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG] = static::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG;
|
||||
$tokenMap[\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG] = static::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG;
|
||||
$tokenMap[\T_ENUM] = static::T_ENUM;
|
||||
$tokenMap[\T_READONLY] = static::T_READONLY;
|
||||
// T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
|
||||
$tokenMap[\T_OPEN_TAG_WITH_ECHO] = static::T_ECHO;
|
||||
// T_CLOSE_TAG is equivalent to ';'
|
||||
$tokenMap[\T_CLOSE_TAG] = ord(';');
|
||||
|
||||
// We have create a map from PHP token IDs to external symbol IDs.
|
||||
// We have created a map from PHP token IDs to external symbol IDs.
|
||||
// Now map them to the internal symbol ID.
|
||||
$fullTokenMap = [];
|
||||
foreach ($tokenMap as $phpToken => $extSymbol) {
|
||||
|
@@ -43,7 +43,7 @@ class PhpVersion {
|
||||
* if it is still under development.
|
||||
*/
|
||||
public static function getNewestSupported(): self {
|
||||
return self::fromComponents(8, 3);
|
||||
return self::fromComponents(8, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -23,7 +23,8 @@ class Standard extends PrettyPrinterAbstract {
|
||||
. ($node->byRef ? '&' : '')
|
||||
. ($node->variadic ? '...' : '')
|
||||
. $this->p($node->var)
|
||||
. ($node->default ? ' = ' . $this->p($node->default) : '');
|
||||
. ($node->default ? ' = ' . $this->p($node->default) : '')
|
||||
. ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : '');
|
||||
}
|
||||
|
||||
protected function pArg(Node\Arg $node): string {
|
||||
@@ -125,6 +126,10 @@ class Standard extends PrettyPrinterAbstract {
|
||||
return '__TRAIT__';
|
||||
}
|
||||
|
||||
protected function pScalar_MagicConst_Property(MagicConst\Property $node): string {
|
||||
return '__PROPERTY__';
|
||||
}
|
||||
|
||||
// Scalars
|
||||
|
||||
private function indentString(string $str): string {
|
||||
@@ -827,7 +832,8 @@ class Standard extends PrettyPrinterAbstract {
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags))
|
||||
. ($node->type ? $this->p($node->type) . ' ' : '')
|
||||
. $this->pCommaSeparated($node->props) . ';';
|
||||
. $this->pCommaSeparated($node->props)
|
||||
. ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : ';');
|
||||
}
|
||||
|
||||
protected function pPropertyItem(Node\PropertyItem $node): string {
|
||||
@@ -835,6 +841,15 @@ class Standard extends PrettyPrinterAbstract {
|
||||
. (null !== $node->default ? ' = ' . $this->p($node->default) : '');
|
||||
}
|
||||
|
||||
protected function pPropertyHook(Node\PropertyHook $node): string {
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. $this->pModifiers($node->flags)
|
||||
. ($node->byRef ? '&' : '') . $node->name
|
||||
. ($node->params ? '(' . $this->pMaybeMultiline($node->params, $this->phpVersion->supportsTrailingCommaInParamList()) . ')' : '')
|
||||
. (\is_array($node->body) ? ' {' . $this->pStmts($node->body) . $this->nl . '}'
|
||||
: ($node->body !== null ? ' => ' . $this->p($node->body) : '') . ';');
|
||||
}
|
||||
|
||||
protected function pStmt_ClassMethod(Stmt\ClassMethod $node): string {
|
||||
return $this->pAttrGroups($node->attrGroups)
|
||||
. $this->pModifiers($node->flags)
|
||||
|
@@ -14,6 +14,7 @@ use PhpParser\Node\Expr\Cast;
|
||||
use PhpParser\Node\IntersectionType;
|
||||
use PhpParser\Node\MatchArm;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\Node\PropertyHook;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\UnionType;
|
||||
@@ -105,6 +106,15 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
|
||||
/** @var int Current indentation level. */
|
||||
protected int $indentLevel;
|
||||
/** @var string String for single level of indentation */
|
||||
private string $indent;
|
||||
/** @var int Width in spaces to indent by. */
|
||||
private int $indentWidth;
|
||||
/** @var bool Whether to use tab indentation. */
|
||||
private bool $useTabs;
|
||||
/** @var int Width in spaces of one tab. */
|
||||
private int $tabWidth = 4;
|
||||
|
||||
/** @var string Newline style. Does not include current indentation. */
|
||||
protected string $newline;
|
||||
/** @var string Newline including current indentation. */
|
||||
@@ -169,12 +179,14 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
* PHP version while specifying an older target (but the result will
|
||||
* of course not be compatible with the older version in that case).
|
||||
* * string $newline: The newline style to use. Should be "\n" (default) or "\r\n".
|
||||
* * string $indent: The indentation to use. Should either be all spaces or a single
|
||||
* tab. Defaults to four spaces (" ").
|
||||
* * bool $shortArraySyntax: Whether to use [] instead of array() as the default array
|
||||
* syntax, if the node does not specify a format. Defaults to whether
|
||||
* the phpVersion support short array syntax.
|
||||
*
|
||||
* @param array{
|
||||
* phpVersion?: PhpVersion, newline?: string, shortArraySyntax?: bool
|
||||
* phpVersion?: PhpVersion, newline?: string, indent?: string, shortArraySyntax?: bool
|
||||
* } $options Dictionary of formatting options
|
||||
*/
|
||||
public function __construct(array $options = []) {
|
||||
@@ -189,6 +201,17 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
$options['shortArraySyntax'] ?? $this->phpVersion->supportsShortArraySyntax();
|
||||
$this->docStringEndToken =
|
||||
$this->phpVersion->supportsFlexibleHeredoc() ? null : '_DOC_STRING_END_' . mt_rand();
|
||||
|
||||
$this->indent = $indent = $options['indent'] ?? ' ';
|
||||
if ($indent === "\t") {
|
||||
$this->useTabs = true;
|
||||
$this->indentWidth = $this->tabWidth;
|
||||
} elseif ($indent === \str_repeat(' ', \strlen($indent))) {
|
||||
$this->useTabs = false;
|
||||
$this->indentWidth = \strlen($indent);
|
||||
} else {
|
||||
throw new \LogicException('Option "indent" must either be all spaces or a single tab');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,24 +230,29 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
*/
|
||||
protected function setIndentLevel(int $level): void {
|
||||
$this->indentLevel = $level;
|
||||
$this->nl = $this->newline . \str_repeat(' ', $level);
|
||||
if ($this->useTabs) {
|
||||
$tabs = \intdiv($level, $this->tabWidth);
|
||||
$spaces = $level % $this->tabWidth;
|
||||
$this->nl = $this->newline . \str_repeat("\t", $tabs) . \str_repeat(' ', $spaces);
|
||||
} else {
|
||||
$this->nl = $this->newline . \str_repeat(' ', $level);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase indentation level.
|
||||
*/
|
||||
protected function indent(): void {
|
||||
$this->indentLevel += 4;
|
||||
$this->nl .= ' ';
|
||||
$this->indentLevel += $this->indentWidth;
|
||||
$this->nl .= $this->indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease indentation level.
|
||||
*/
|
||||
protected function outdent(): void {
|
||||
assert($this->indentLevel >= 4);
|
||||
$this->indentLevel -= 4;
|
||||
$this->nl = $this->newline . str_repeat(' ', $this->indentLevel);
|
||||
assert($this->indentLevel >= $this->indentWidth);
|
||||
$this->setIndentLevel($this->indentLevel - $this->indentWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -536,7 +564,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
$this->initializeModifierChangeMap();
|
||||
|
||||
$this->resetState();
|
||||
$this->origTokens = new TokenStream($origTokens);
|
||||
$this->origTokens = new TokenStream($origTokens, $this->tabWidth);
|
||||
|
||||
$this->preprocessNodes($stmts);
|
||||
|
||||
@@ -708,7 +736,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
$result .= $extraLeft;
|
||||
|
||||
$origIndentLevel = $this->indentLevel;
|
||||
$this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment);
|
||||
$this->setIndentLevel(max($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment, 0));
|
||||
|
||||
// If it's the same node that was previously in this position, it certainly doesn't
|
||||
// need fixup. It's important to check this here, because our fixup checks are more
|
||||
@@ -811,7 +839,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
\assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
|
||||
|
||||
$origIndentLevel = $this->indentLevel;
|
||||
$lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment;
|
||||
$lastElemIndentLevel = max($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment, 0);
|
||||
$this->setIndentLevel($lastElemIndentLevel);
|
||||
|
||||
$comments = $arrItem->getComments();
|
||||
@@ -1195,6 +1223,9 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
. ($modifiers & Modifiers::PUBLIC ? 'public ' : '')
|
||||
. ($modifiers & Modifiers::PROTECTED ? 'protected ' : '')
|
||||
. ($modifiers & Modifiers::PRIVATE ? 'private ' : '')
|
||||
. ($modifiers & Modifiers::PUBLIC_SET ? 'public(set) ' : '')
|
||||
. ($modifiers & Modifiers::PROTECTED_SET ? 'protected(set) ' : '')
|
||||
. ($modifiers & Modifiers::PRIVATE_SET ? 'private(set) ' : '')
|
||||
. ($modifiers & Modifiers::STATIC ? 'static ' : '')
|
||||
. ($modifiers & Modifiers::READONLY ? 'readonly ' : '');
|
||||
}
|
||||
@@ -1517,6 +1548,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
Stmt\UseUse::class . '->uses' => ', ',
|
||||
MatchArm::class . '->conds' => ', ',
|
||||
AttributeGroup::class . '->attrs' => ', ',
|
||||
PropertyHook::class . '->params' => ', ',
|
||||
|
||||
// statement lists
|
||||
Expr\Closure::class . '->stmts' => "\n",
|
||||
@@ -1554,10 +1586,15 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
Expr\Closure::class . '->attrGroups' => ' ',
|
||||
Expr\ArrowFunction::class . '->attrGroups' => ' ',
|
||||
Param::class . '->attrGroups' => ' ',
|
||||
PropertyHook::class . '->attrGroups' => ' ',
|
||||
|
||||
Stmt\Switch_::class . '->cases' => "\n",
|
||||
Stmt\TraitUse::class . '->adaptations' => "\n",
|
||||
Stmt\TryCatch::class . '->stmts' => "\n",
|
||||
Stmt\While_::class . '->stmts' => "\n",
|
||||
PropertyHook::class . '->body' => "\n",
|
||||
Stmt\Property::class . '->hooks' => "\n",
|
||||
Param::class . '->hooks' => "\n",
|
||||
|
||||
// dummy for top-level context
|
||||
'File->stmts' => "\n",
|
||||
@@ -1641,6 +1678,7 @@ abstract class PrettyPrinterAbstract implements PrettyPrinter {
|
||||
Stmt\Property::class . '->flags' => ['pModifiers', \T_VARIABLE],
|
||||
PrintableNewAnonClassNode::class . '->flags' => ['pModifiers', \T_CLASS],
|
||||
Param::class . '->flags' => ['pModifiers', \T_VARIABLE],
|
||||
PropertyHook::class . '->flags' => ['pModifiers', \T_STRING],
|
||||
Expr\Closure::class . '->static' => ['pStatic', \T_FUNCTION],
|
||||
Expr\ArrowFunction::class . '->static' => ['pStatic', \T_FN],
|
||||
//Stmt\TraitUseAdaptation\Alias::class . '->newModifier' => 0, // TODO
|
||||
|
@@ -17,6 +17,11 @@ if (!\function_exists('PhpParser\defineCompatibilityTokens')) {
|
||||
'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG',
|
||||
'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG',
|
||||
'T_READONLY',
|
||||
// PHP 8.4
|
||||
'T_PROPERTY_C',
|
||||
'T_PUBLIC_SET',
|
||||
'T_PROTECTED_SET',
|
||||
'T_PRIVATE_SET',
|
||||
];
|
||||
|
||||
// PHP-Parser might be used together with another library that also emulates some or all
|
||||
|
@@ -90,6 +90,76 @@ parameters:
|
||||
count: 1
|
||||
path: lib/PhpParser/Lexer/Emulative.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Expr/ArrayItem.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Expr/ClosureUse.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Scalar/DNumber.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Scalar/Encapsed.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Scalar/EncapsedStringPart.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Scalar/LNumber.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Stmt/DeclareDeclare.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Stmt/PropertyProperty.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Stmt/StaticVar.php
|
||||
|
||||
-
|
||||
message: "#^If condition is always false\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Node/Stmt/UseUse.php
|
||||
|
||||
-
|
||||
message: "#^Constant T_PRIVATE_SET not found\\.$#"
|
||||
count: 2
|
||||
path: lib/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php
|
||||
|
||||
-
|
||||
message: "#^Constant T_PROTECTED_SET not found\\.$#"
|
||||
count: 2
|
||||
path: lib/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php
|
||||
|
||||
-
|
||||
message: "#^Constant T_PUBLIC_SET not found\\.$#"
|
||||
count: 2
|
||||
path: lib/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php
|
||||
|
||||
-
|
||||
message: "#^Constant T_PROPERTY_C not found\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php
|
||||
|
||||
-
|
||||
message: "#^Method PhpParser\\\\NodeDumper\\:\\:__construct\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -155,76 +225,11 @@ parameters:
|
||||
count: 1
|
||||
path: lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_ATTRIBUTE\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_COALESCE_EQUAL\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_ECHO\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_ENUM\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_FN\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_MATCH\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_NAME_FULLY_QUALIFIED\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_NAME_QUALIFIED\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_NAME_RELATIVE\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_NULLSAFE_OBJECT_OPERATOR\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_PAAMAYIM_NEKUDOTAYIM\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Access to undefined constant static\\(PhpParser\\\\ParserAbstract\\)\\:\\:T_READONLY\\.$#"
|
||||
count: 1
|
||||
path: lib/PhpParser/ParserAbstract.php
|
||||
|
||||
-
|
||||
message: "#^Unary operation \"\\+\" on string results in an error\\.$#"
|
||||
count: 1
|
||||
|
@@ -227,6 +227,16 @@ class ParamTest extends \PHPUnit\Framework\TestCase {
|
||||
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PROTECTED),
|
||||
$node
|
||||
);
|
||||
|
||||
$node = $this->createParamBuilder('test')
|
||||
->makeProtectedSet()
|
||||
->getNode()
|
||||
;
|
||||
|
||||
$this->assertEquals(
|
||||
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PROTECTED_SET),
|
||||
$node
|
||||
);
|
||||
}
|
||||
|
||||
public function testMakePrivate(): void {
|
||||
@@ -239,6 +249,16 @@ class ParamTest extends \PHPUnit\Framework\TestCase {
|
||||
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PRIVATE),
|
||||
$node
|
||||
);
|
||||
|
||||
$node = $this->createParamBuilder('test')
|
||||
->makePrivateSet()
|
||||
->getNode()
|
||||
;
|
||||
|
||||
$this->assertEquals(
|
||||
new Node\Param(new Expr\Variable('test'), null, null, false, false, [], Modifiers::PRIVATE_SET),
|
||||
$node
|
||||
);
|
||||
}
|
||||
|
||||
public function testMakeReadonly(): void {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace PhpParser\Builder;
|
||||
|
||||
use PhpParser\Comment;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Modifiers;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Attribute;
|
||||
@@ -10,6 +11,8 @@ use PhpParser\Node\AttributeGroup;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\PropertyHook;
|
||||
use PhpParser\Node\PropertyItem;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Scalar\Int_;
|
||||
use PhpParser\Node\Stmt;
|
||||
@@ -29,9 +32,7 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(
|
||||
Modifiers::PRIVATE | Modifiers::STATIC,
|
||||
[
|
||||
new \PhpParser\Node\PropertyItem('test')
|
||||
]
|
||||
[new PropertyItem('test')]
|
||||
),
|
||||
$node
|
||||
);
|
||||
@@ -44,9 +45,7 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(
|
||||
Modifiers::PROTECTED,
|
||||
[
|
||||
new \PhpParser\Node\PropertyItem('test')
|
||||
]
|
||||
[new PropertyItem('test')]
|
||||
),
|
||||
$node
|
||||
);
|
||||
@@ -59,9 +58,7 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(
|
||||
Modifiers::PUBLIC,
|
||||
[
|
||||
new \PhpParser\Node\PropertyItem('test')
|
||||
]
|
||||
[new PropertyItem('test')]
|
||||
),
|
||||
$node
|
||||
);
|
||||
@@ -74,12 +71,37 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(
|
||||
Modifiers::READONLY,
|
||||
[
|
||||
new \PhpParser\Node\PropertyItem('test')
|
||||
]
|
||||
[new PropertyItem('test')]
|
||||
),
|
||||
$node
|
||||
);
|
||||
|
||||
$node = $this->createPropertyBuilder('test')
|
||||
->makeFinal()
|
||||
->getNode();
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(Modifiers::FINAL, [new PropertyItem('test')]),
|
||||
$node);
|
||||
|
||||
$node = $this->createPropertyBuilder('test')
|
||||
->makePrivateSet()
|
||||
->getNode();
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(Modifiers::PRIVATE_SET, [new PropertyItem('test')]),
|
||||
$node);
|
||||
|
||||
$node = $this->createPropertyBuilder('test')
|
||||
->makeProtectedSet()
|
||||
->getNode();
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(Modifiers::PROTECTED_SET, [new PropertyItem('test')]),
|
||||
$node);
|
||||
}
|
||||
|
||||
public function testAbstractWithoutHook() {
|
||||
$this->expectException(Error::class);
|
||||
$this->expectExceptionMessage('Only hooked properties may be declared abstract');
|
||||
$this->createPropertyBuilder('test')->makeAbstract()->getNode();
|
||||
}
|
||||
|
||||
public function testDocComment(): void {
|
||||
@@ -136,6 +158,23 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddHook(): void {
|
||||
$get = new PropertyHook('get', null);
|
||||
$set = new PropertyHook('set', null);
|
||||
$node = $this->createPropertyBuilder('test')
|
||||
->addHook($get)
|
||||
->addHook($set)
|
||||
->makeAbstract()
|
||||
->getNode();
|
||||
$this->assertEquals(
|
||||
new Stmt\Property(
|
||||
Modifiers::ABSTRACT,
|
||||
[new PropertyItem('test')],
|
||||
[], null, [],
|
||||
[$get, $set]),
|
||||
$node);
|
||||
}
|
||||
|
||||
public static function provideTestDefaultValues() {
|
||||
return [
|
||||
[
|
||||
|
@@ -4,6 +4,7 @@ namespace PhpParser;
|
||||
|
||||
use PhpParser\Builder\Class_;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use PhpParser\Node\Scalar;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Expr;
|
||||
@@ -222,4 +223,14 @@ class BuilderHelpersTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->expectExceptionMessage('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
|
||||
BuilderHelpers::normalizeAttribute('test');
|
||||
}
|
||||
|
||||
public function testNormalizeValueEnum() {
|
||||
if (\PHP_VERSION_ID <= 80100) {
|
||||
$this->markTestSkipped('Enums are supported since PHP 8.1');
|
||||
}
|
||||
|
||||
include __DIR__ . '/../fixtures/Suit.php';
|
||||
|
||||
$this->assertEquals(new Expr\ClassConstFetch(new FullyQualified(\Suit::class), new Identifier('Hearts')), BuilderHelpers::normalizeValue(\Suit::Hearts));
|
||||
}
|
||||
}
|
||||
|
@@ -91,6 +91,9 @@ class EmulativeTest extends LexerTest {
|
||||
|
||||
public static function provideTestReplaceKeywords() {
|
||||
return [
|
||||
// PHP 8.4
|
||||
['__PROPERTY__', \T_PROPERTY_C],
|
||||
|
||||
// PHP 8.0
|
||||
['match', \T_MATCH],
|
||||
|
||||
@@ -390,6 +393,37 @@ class EmulativeTest extends LexerTest {
|
||||
[\T_READONLY, 'readonly'],
|
||||
[ord('('), '('],
|
||||
]],
|
||||
|
||||
// PHP 8.4: Asymmetric visibility modifiers
|
||||
['private(set)', [
|
||||
[\T_PRIVATE_SET, 'private(set)']
|
||||
]],
|
||||
['PROTECTED(SET)', [
|
||||
[\T_PROTECTED_SET, 'PROTECTED(SET)']
|
||||
]],
|
||||
['Public(Set)', [
|
||||
[\T_PUBLIC_SET, 'Public(Set)']
|
||||
]],
|
||||
['public (set)', [
|
||||
[\T_PUBLIC, 'public'],
|
||||
[\ord('('), '('],
|
||||
[\T_STRING, 'set'],
|
||||
[\ord(')'), ')'],
|
||||
]],
|
||||
['->public(set)', [
|
||||
[\T_OBJECT_OPERATOR, '->'],
|
||||
[\T_STRING, 'public'],
|
||||
[\ord('('), '('],
|
||||
[\T_STRING, 'set'],
|
||||
[\ord(')'), ')'],
|
||||
]],
|
||||
['?-> public(set)', [
|
||||
[\T_NULLSAFE_OBJECT_OPERATOR, '?->'],
|
||||
[\T_STRING, 'public'],
|
||||
[\ord('('), '('],
|
||||
[\T_STRING, 'set'],
|
||||
[\ord(')'), ')'],
|
||||
]],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -424,6 +458,19 @@ class EmulativeTest extends LexerTest {
|
||||
[\T_ENCAPSED_AND_WHITESPACE, ' baz'],
|
||||
[ord('"'), '"'],
|
||||
]],
|
||||
['8.4', '__PROPERTY__', [[\T_PROPERTY_C, '__PROPERTY__']]],
|
||||
['8.3', '__PROPERTY__', [[\T_STRING, '__PROPERTY__']]],
|
||||
['8.4', '__property__', [[\T_PROPERTY_C, '__property__']]],
|
||||
['8.3', '__property__', [[\T_STRING, '__property__']]],
|
||||
['8.4', 'public(set)', [
|
||||
[\T_PUBLIC_SET, 'public(set)'],
|
||||
]],
|
||||
['8.3', 'public(set)', [
|
||||
[\T_PUBLIC, 'public'],
|
||||
[\ord('('), '('],
|
||||
[\T_STRING, 'set'],
|
||||
[\ord(')'), ')']
|
||||
]],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
18
test/PhpParser/ModifiersTest.php
Normal file
18
test/PhpParser/ModifiersTest.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ModifiersTest extends TestCase {
|
||||
public function testToString() {
|
||||
$this->assertSame('public', Modifiers::toString(Modifiers::PUBLIC));
|
||||
}
|
||||
|
||||
public function testToStringInvalid() {
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Unknown modifier 3');
|
||||
Modifiers::toString(Modifiers::PUBLIC | Modifiers::PROTECTED);
|
||||
}
|
||||
}
|
@@ -14,6 +14,9 @@ class ParamTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertFalse($node->isProtected());
|
||||
$this->assertFalse($node->isPrivate());
|
||||
$this->assertFalse($node->isReadonly());
|
||||
$this->assertFalse($node->isPublicSet());
|
||||
$this->assertFalse($node->isProtectedSet());
|
||||
$this->assertFalse($node->isPrivateSet());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -34,4 +37,28 @@ class ParamTest extends \PHPUnit\Framework\TestCase {
|
||||
['readonly'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testSetVisibility() {
|
||||
$node = new Param(new Variable('foo'));
|
||||
$node->flags = Modifiers::PRIVATE_SET;
|
||||
$this->assertTrue($node->isPrivateSet());
|
||||
$node->flags = Modifiers::PROTECTED_SET;
|
||||
$this->assertTrue($node->isProtectedSet());
|
||||
$node->flags = Modifiers::PUBLIC_SET;
|
||||
$this->assertTrue($node->isPublicSet());
|
||||
}
|
||||
|
||||
public function testPromotedPropertyWithoutVisibilityModifier(): void {
|
||||
$node = new Param(new Variable('foo'));
|
||||
$get = new PropertyHook('get', null);
|
||||
$node->hooks[] = $get;
|
||||
|
||||
$this->assertTrue($node->isPromoted());
|
||||
$this->assertTrue($node->isPublic());
|
||||
}
|
||||
|
||||
public function testNonPromotedPropertyIsNotPublic(): void {
|
||||
$node = new Param(new Variable('foo'));
|
||||
$this->assertFalse($node->isPublic());
|
||||
}
|
||||
}
|
||||
|
89
test/PhpParser/Node/PropertyHookTest.php
Normal file
89
test/PhpParser/Node/PropertyHookTest.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node;
|
||||
|
||||
use PhpParser\Modifiers;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Scalar\Int_;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
class PropertyHookTest extends \PHPUnit\Framework\TestCase {
|
||||
/**
|
||||
* @dataProvider provideModifiers
|
||||
*/
|
||||
public function testModifiers($modifier): void {
|
||||
$node = new PropertyHook(
|
||||
'get',
|
||||
null,
|
||||
[
|
||||
'flags' => constant(Modifiers::class . '::' . strtoupper($modifier)),
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertTrue($node->{'is' . $modifier}());
|
||||
}
|
||||
|
||||
public function testNoModifiers(): void {
|
||||
$node = new PropertyHook('get', null);
|
||||
|
||||
$this->assertFalse($node->isFinal());
|
||||
}
|
||||
|
||||
public static function provideModifiers() {
|
||||
return [
|
||||
['final'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetStmts(): void {
|
||||
$expr = new Variable('test');
|
||||
$get = new PropertyHook('get', $expr);
|
||||
$this->assertEquals([new Return_($expr)], $get->getStmts());
|
||||
|
||||
$set = new PropertyHook('set', $expr, [], ['propertyName' => 'abc']);
|
||||
$this->assertEquals([
|
||||
new Expression(new Assign(new PropertyFetch(new Variable('this'), 'abc'), $expr))
|
||||
], $set->getStmts());
|
||||
}
|
||||
|
||||
public function testGetStmtsSetHookFromParser(): void {
|
||||
$parser = (new ParserFactory())->createForNewestSupportedVersion();
|
||||
$prettyPrinter = new Standard();
|
||||
$stmts = $parser->parse(<<<'CODE'
|
||||
<?php
|
||||
class Test {
|
||||
public $prop1 { set => 123; }
|
||||
|
||||
public function __construct(public $prop2 { set => 456; }) {}
|
||||
}
|
||||
CODE);
|
||||
|
||||
$hook1 = $stmts[0]->stmts[0]->hooks[0];
|
||||
$this->assertEquals('$this->prop1 = 123;', $prettyPrinter->prettyPrint($hook1->getStmts()));
|
||||
|
||||
$hook2 = $stmts[0]->stmts[1]->params[0]->hooks[0];
|
||||
$this->assertEquals('$this->prop2 = 456;', $prettyPrinter->prettyPrint($hook2->getStmts()));
|
||||
}
|
||||
|
||||
public function testGetStmtsUnknownHook(): void {
|
||||
$expr = new Variable('test');
|
||||
$hook = new PropertyHook('foobar', $expr);
|
||||
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('Unknown property hook "foobar"');
|
||||
$hook->getStmts();
|
||||
}
|
||||
|
||||
public function testGetStmtsSetHookWithoutPropertyName(): void {
|
||||
$expr = new Variable('test');
|
||||
$set = new PropertyHook('set', $expr);
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('Can only use getStmts() on a "set" hook if the "propertyName" attribute is set');
|
||||
$set->getStmts();
|
||||
}
|
||||
}
|
@@ -25,6 +25,9 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
$this->assertFalse($node->isPrivate());
|
||||
$this->assertFalse($node->isStatic());
|
||||
$this->assertFalse($node->isReadonly());
|
||||
$this->assertFalse($node->isPublicSet());
|
||||
$this->assertFalse($node->isProtectedSet());
|
||||
$this->assertFalse($node->isPrivateSet());
|
||||
}
|
||||
|
||||
public function testStaticImplicitlyPublic(): void {
|
||||
@@ -45,4 +48,23 @@ class PropertyTest extends \PHPUnit\Framework\TestCase {
|
||||
['readonly'],
|
||||
];
|
||||
}
|
||||
|
||||
public function testSetVisibility() {
|
||||
$node = new Property(Modifiers::PRIVATE_SET, []);
|
||||
$this->assertTrue($node->isPrivateSet());
|
||||
$node = new Property(Modifiers::PROTECTED_SET, []);
|
||||
$this->assertTrue($node->isProtectedSet());
|
||||
$node = new Property(Modifiers::PUBLIC_SET, []);
|
||||
$this->assertTrue($node->isPublicSet());
|
||||
}
|
||||
|
||||
public function testIsFinal() {
|
||||
$node = new Property(Modifiers::FINAL, []);
|
||||
$this->assertTrue($node->isFinal());
|
||||
}
|
||||
|
||||
public function testIsAbstract() {
|
||||
$node = new Property(Modifiers::ABSTRACT, []);
|
||||
$this->assertTrue($node->isAbstract());
|
||||
}
|
||||
}
|
||||
|
@@ -261,6 +261,7 @@ PHP;
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": [],
|
||||
"hooks": [],
|
||||
"attributes": {
|
||||
"startLine": 4,
|
||||
"startTokenPos": 9,
|
||||
@@ -302,6 +303,7 @@ PHP;
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": [],
|
||||
"hooks": [],
|
||||
"attributes": {
|
||||
"startLine": 4,
|
||||
"startTokenPos": 17,
|
||||
@@ -464,7 +466,8 @@ JSON;
|
||||
"value": 0
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": []
|
||||
"attrGroups": [],
|
||||
"hooks": []
|
||||
},
|
||||
{
|
||||
"nodeType": "Param",
|
||||
@@ -505,7 +508,8 @@ JSON;
|
||||
"value": 1
|
||||
},
|
||||
"flags": 0,
|
||||
"attrGroups": []
|
||||
"attrGroups": [],
|
||||
"hooks": []
|
||||
}
|
||||
],
|
||||
"returnType": null,
|
||||
|
@@ -201,6 +201,18 @@ class A extends B implements C, D {
|
||||
public const X A = X::Bar;
|
||||
public const X\Foo B = X\Foo::Bar;
|
||||
public const \X\Foo C = \X\Foo::Bar;
|
||||
|
||||
public Foo $foo {
|
||||
#[X]
|
||||
set(#[X] Bar $v) {}
|
||||
}
|
||||
|
||||
public function __construct(
|
||||
public Foo $bar {
|
||||
#[X]
|
||||
set(#[X] Bar $v) {}
|
||||
}
|
||||
) {}
|
||||
}
|
||||
|
||||
#[X]
|
||||
@@ -269,6 +281,18 @@ class A extends \NS\B implements \NS\C, \NS\D
|
||||
public const \NS\X A = \NS\X::Bar;
|
||||
public const \NS\X\Foo B = \NS\X\Foo::Bar;
|
||||
public const \X\Foo C = \X\Foo::Bar;
|
||||
public \NS\Foo $foo {
|
||||
#[\NS\X]
|
||||
set(#[\NS\X] \NS\Bar $v) {
|
||||
}
|
||||
}
|
||||
public function __construct(public \NS\Foo $bar {
|
||||
#[\NS\X]
|
||||
set(#[\NS\X] \NS\Bar $v) {
|
||||
}
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
#[\NS\X]
|
||||
interface A extends \NS\C, \NS\D
|
||||
@@ -543,7 +567,7 @@ EOC;
|
||||
}
|
||||
|
||||
private function parseAndResolve(string $code): array {
|
||||
$parser = new PhpParser\Parser\Php7(new PhpParser\Lexer\Emulative());
|
||||
$parser = new PhpParser\Parser\Php8(new PhpParser\Lexer\Emulative());
|
||||
$traverser = new PhpParser\NodeTraverser();
|
||||
$traverser->addVisitor(new NameResolver());
|
||||
|
||||
|
@@ -10,18 +10,26 @@ use PhpParser\Node\InterpolatedStringPart;
|
||||
use PhpParser\Node\Scalar\Int_;
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Parser\Php7;
|
||||
use PhpParser\PrettyPrinter\Standard;
|
||||
|
||||
class PrettyPrinterTest extends CodeTestAbstract {
|
||||
/** @return array{0: Parser, 1: PrettyPrinter} */
|
||||
private function createParserAndPrinter(array $options): array {
|
||||
$parserVersion = $options['parserVersion'] ?? $options['version'] ?? null;
|
||||
$printerVersion = $options['version'] ?? null;
|
||||
$indent = isset($options['indent']) ? json_decode($options['indent']) : null;
|
||||
$factory = new ParserFactory();
|
||||
$parser = $factory->createForVersion($parserVersion !== null
|
||||
? PhpVersion::fromString($parserVersion) : PhpVersion::getNewestSupported());
|
||||
$prettyPrinter = new Standard([
|
||||
'phpVersion' => $printerVersion !== null ? PhpVersion::fromString($printerVersion) : null,
|
||||
'indent' => $indent,
|
||||
]);
|
||||
return [$parser, $prettyPrinter];
|
||||
}
|
||||
|
||||
protected function doTestPrettyPrintMethod($method, $name, $code, $expected, $modeLine) {
|
||||
$lexer = new Lexer\Emulative();
|
||||
$parser = new Parser\Php7($lexer);
|
||||
|
||||
$options = $this->parseModeLine($modeLine);
|
||||
$version = isset($options['version']) ? PhpVersion::fromString($options['version']) : null;
|
||||
$prettyPrinter = new Standard(['phpVersion' => $version]);
|
||||
|
||||
[$parser, $prettyPrinter] = $this->createParserAndPrinter($this->parseModeLine($modeLine));
|
||||
$output = canonicalize($prettyPrinter->$method($parser->parse($code)));
|
||||
$this->assertSame($expected, $output, $name);
|
||||
}
|
||||
@@ -181,12 +189,9 @@ class PrettyPrinterTest extends CodeTestAbstract {
|
||||
* @dataProvider provideTestFormatPreservingPrint
|
||||
*/
|
||||
public function testFormatPreservingPrint($name, $code, $modification, $expected, $modeLine): void {
|
||||
$lexer = new Lexer\Emulative();
|
||||
$parser = new Parser\Php7($lexer);
|
||||
[$parser, $printer] = $this->createParserAndPrinter($this->parseModeLine($modeLine));
|
||||
$traverser = new NodeTraverser(new NodeVisitor\CloningVisitor());
|
||||
|
||||
$printer = new PrettyPrinter\Standard();
|
||||
|
||||
$oldStmts = $parser->parse($code);
|
||||
$oldTokens = $parser->getTokens();
|
||||
|
||||
@@ -222,14 +227,9 @@ CODE
|
||||
* the pretty printer tests (i.e. returns the input if no changes occurred).
|
||||
*/
|
||||
|
||||
$lexer = new Lexer\Emulative();
|
||||
|
||||
$parser = new Php7($lexer);
|
||||
|
||||
[$parser, $printer] = $this->createParserAndPrinter($this->parseModeLine($modeLine));
|
||||
$traverser = new NodeTraverser(new NodeVisitor\CloningVisitor());
|
||||
|
||||
$printer = new PrettyPrinter\Standard();
|
||||
|
||||
try {
|
||||
$oldStmts = $parser->parse($code);
|
||||
} catch (Error $e) {
|
||||
@@ -299,4 +299,10 @@ CODE
|
||||
$this->expectExceptionMessage('Option "newline" must be one of "\n" or "\r\n"');
|
||||
new PrettyPrinter\Standard(['newline' => 'foo']);
|
||||
}
|
||||
|
||||
public function testInvalidIndent(): void {
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('Option "indent" must either be all spaces or a single tab');
|
||||
new PrettyPrinter\Standard(['indent' => "\t "]);
|
||||
}
|
||||
}
|
||||
|
9
test/code/formatPreservation/group_use.test
Normal file
9
test/code/formatPreservation/group_use.test
Normal file
@@ -0,0 +1,9 @@
|
||||
Group use should include trailing semicolon
|
||||
-----
|
||||
<?php
|
||||
use A\{B, C};
|
||||
-----
|
||||
$stmts[0] = new Stmt\Use_([new Node\UseItem(new Node\Name('A\B'))]);
|
||||
-----
|
||||
<?php
|
||||
use A\B;
|
70
test/code/formatPreservation/indent.test
Normal file
70
test/code/formatPreservation/indent.test
Normal file
@@ -0,0 +1,70 @@
|
||||
Indentation
|
||||
-----
|
||||
<?php
|
||||
$x;
|
||||
-----
|
||||
$stmts[0] = new Stmt\If_(new Expr\Variable('a'), ['stmts' => $stmts]);
|
||||
-----
|
||||
!!indent=" "
|
||||
<?php
|
||||
if ($a) {
|
||||
$x;
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
$x;
|
||||
-----
|
||||
$stmts[0] = new Stmt\If_(new Expr\Variable('a'), ['stmts' => $stmts]);
|
||||
-----
|
||||
!!indent="\t"
|
||||
<?php
|
||||
if ($a) {
|
||||
@@{"\t"}@@$x;
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
if ($a) {
|
||||
@@{"\t"}@@$x;
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[] = new Stmt\Expression(new Expr\Variable('y'));
|
||||
-----
|
||||
!!indent="\t"
|
||||
<?php
|
||||
if ($a) {
|
||||
@@{"\t"}@@$x;
|
||||
@@{"\t"}@@$y;
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
array_merge(
|
||||
[
|
||||
$x,
|
||||
$y,
|
||||
]
|
||||
);
|
||||
-----
|
||||
$call = $stmts[0]->expr;
|
||||
$stmts[0]->expr = new Expr\StaticCall(new Node\Name\FullyQualified('Compat'), $call->name, $call->args);
|
||||
-----
|
||||
<?php
|
||||
\Compat::array_merge([
|
||||
$x,
|
||||
$y,
|
||||
]);
|
||||
-----
|
||||
<?php
|
||||
if ($a) {
|
||||
if (
|
||||
$b
|
||||
) {}
|
||||
}
|
||||
-----
|
||||
$stmts[0] = new Stmt\While_($stmts[0]->cond, $stmts[0]->stmts);
|
||||
-----
|
||||
<?php
|
||||
while ($a) {
|
||||
if (
|
||||
$b
|
||||
) {}
|
||||
}
|
128
test/code/formatPreservation/property_hooks.test
Normal file
128
test/code/formatPreservation/property_hooks.test
Normal file
@@ -0,0 +1,128 @@
|
||||
Property hooks
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop
|
||||
{
|
||||
get => 42;
|
||||
}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->hooks[] = new Node\PropertyHook('set', new Scalar\Int_(123));
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop
|
||||
{
|
||||
get => 42;
|
||||
set => 123;
|
||||
}
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public function __construct(
|
||||
public $prop
|
||||
{ get => 42; }
|
||||
) {}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->params[0]->hooks[] = new Node\PropertyHook('set', new Scalar\Int_(123));
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public function __construct(
|
||||
public $prop
|
||||
{ get => 42;
|
||||
set => 123; }
|
||||
) {}
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
set
|
||||
{
|
||||
$a;
|
||||
}
|
||||
}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->hooks[0]->body[] = new Stmt\Expression(new Expr\Variable('b'));
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
set
|
||||
{
|
||||
$a;
|
||||
$b;
|
||||
}
|
||||
}
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
get
|
||||
=> 42;
|
||||
}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->hooks[0]->flags = Modifiers::FINAL;
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
final get
|
||||
=> 42;
|
||||
}
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
// For now, just make sure this works.
|
||||
class Test {
|
||||
public $prop {
|
||||
get
|
||||
=> 42;
|
||||
}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->hooks[0]->body = [new Stmt\Return_(new Scalar\Int_(24))];
|
||||
-----
|
||||
<?php
|
||||
// For now, just make sure this works.
|
||||
class Test {
|
||||
public $prop {
|
||||
get {
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
-----
|
||||
<?php
|
||||
// For now, just make sure this works.
|
||||
class Test {
|
||||
public $prop1 {
|
||||
& get;
|
||||
}
|
||||
public $prop2 {
|
||||
& get;
|
||||
}
|
||||
}
|
||||
-----
|
||||
$stmts[0]->stmts[0]->hooks[0]->body = new Scalar\Int_(24);
|
||||
$stmts[0]->stmts[1]->hooks[0]->body = [new Stmt\Return_(new Scalar\Int_(24))];
|
||||
-----
|
||||
<?php
|
||||
// For now, just make sure this works.
|
||||
class Test {
|
||||
public $prop1 {
|
||||
&get => 24;
|
||||
}
|
||||
public $prop2 {
|
||||
&get {
|
||||
return 24;
|
||||
}
|
||||
}
|
||||
}
|
@@ -31,6 +31,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Nop(
|
||||
comments: array(
|
||||
|
@@ -714,6 +714,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -869,6 +871,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -883,6 +887,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -984,6 +990,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1016,6 +1024,8 @@ array(
|
||||
name: foo
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -1029,6 +1039,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1058,6 +1070,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1087,6 +1101,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1118,6 +1134,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1156,6 +1174,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -1183,6 +1203,8 @@ array(
|
||||
var: Expr_Error(
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@@ -1352,7 +1374,7 @@ class B {
|
||||
const X = 1
|
||||
}
|
||||
-----
|
||||
Syntax error, unexpected T_PUBLIC, expecting ';' from 6:5 to 6:10
|
||||
Syntax error, unexpected T_PUBLIC, expecting ';' or '{' from 6:5 to 6:10
|
||||
Syntax error, unexpected '}', expecting ';' from 12:1 to 12:1
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
@@ -1379,6 +1401,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: /** @var ?string */
|
||||
)
|
||||
@@ -1405,6 +1429,8 @@ array(
|
||||
name: s
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
335
test/code/parser/expr/alternative_array_syntax.test
Normal file
335
test/code/parser/expr/alternative_array_syntax.test
Normal file
@@ -0,0 +1,335 @@
|
||||
Alternative array syntax
|
||||
-----
|
||||
<?php
|
||||
|
||||
$a{'b'};
|
||||
$a{'b'}();
|
||||
$a->b{'c'};
|
||||
$a->b(){'c'};
|
||||
A::$b{'c'};
|
||||
A{0};
|
||||
A::B{0};
|
||||
new $array{'className'};
|
||||
new $a->b{'c'}();
|
||||
-----
|
||||
!!version=7.4
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_StaticPropertyFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: VarLikeIdentifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: A
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: Identifier(
|
||||
name: B
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: array
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: className
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
|
||||
$a{'b'};
|
||||
$a{'b'}();
|
||||
$a->b{'c'};
|
||||
$a->b(){'c'};
|
||||
A::$b{'c'};
|
||||
A{0};
|
||||
A::B{0};
|
||||
new $array{'className'};
|
||||
new $a->b{'c'}();
|
||||
-----
|
||||
Syntax error, unexpected '{' from 3:3 to 3:3
|
||||
Syntax error, unexpected '{' from 4:3 to 4:3
|
||||
Syntax error, unexpected '{' from 5:6 to 5:6
|
||||
Syntax error, unexpected '{' from 6:8 to 6:8
|
||||
Syntax error, unexpected '{' from 7:6 to 7:6
|
||||
Syntax error, unexpected '{' from 8:2 to 8:2
|
||||
Syntax error, unexpected '{' from 9:5 to 9:5
|
||||
Syntax error, unexpected '{' from 10:11 to 10:11
|
||||
Syntax error, unexpected '{' from 11:10 to 11:10
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
expr: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
)
|
||||
1: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
)
|
||||
3: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_StaticPropertyFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: VarLikeIdentifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
)
|
||||
9: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
10: Stmt_Expression(
|
||||
expr: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: A
|
||||
)
|
||||
)
|
||||
)
|
||||
11: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
12: Stmt_Expression(
|
||||
expr: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: Identifier(
|
||||
name: B
|
||||
)
|
||||
)
|
||||
)
|
||||
13: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
14: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_Variable(
|
||||
name: array
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
15: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: className
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
16: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
17: Stmt_Block(
|
||||
stmts: array(
|
||||
0: Stmt_Expression(
|
||||
expr: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@@ -32,6 +32,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -60,6 +62,8 @@ array(
|
||||
default: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -86,6 +90,8 @@ array(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -112,6 +118,8 @@ array(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -138,6 +146,8 @@ array(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -150,6 +160,8 @@ array(
|
||||
name: rest
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -192,6 +204,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -204,6 +218,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -235,6 +251,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -247,6 +265,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -28,6 +28,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@@ -60,6 +62,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@@ -120,6 +124,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@@ -162,6 +168,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
|
@@ -7,6 +7,13 @@ exit('Die!');
|
||||
die;
|
||||
die();
|
||||
die('Exit!');
|
||||
|
||||
exit(status: 42);
|
||||
exit(...$args);
|
||||
exit($a, $b);
|
||||
\exit($a);
|
||||
exit(...);
|
||||
DIE($a, $b);
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
@@ -43,4 +50,118 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name(
|
||||
name: exit
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: Identifier(
|
||||
name: status
|
||||
)
|
||||
value: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name(
|
||||
name: exit
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: args
|
||||
)
|
||||
byRef: false
|
||||
unpack: true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name(
|
||||
name: exit
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
1: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: b
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
9: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name_FullyQualified(
|
||||
name: exit
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
10: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name(
|
||||
name: exit
|
||||
)
|
||||
args: array(
|
||||
0: VariadicPlaceholder(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
11: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Name(
|
||||
name: DIE
|
||||
)
|
||||
args: array(
|
||||
0: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
1: Arg(
|
||||
name: null
|
||||
value: Expr_Variable(
|
||||
name: b
|
||||
)
|
||||
byRef: false
|
||||
unpack: false
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@@ -9,7 +9,6 @@ ${'a'}();
|
||||
$$a();
|
||||
$$$a();
|
||||
$a['b']();
|
||||
$a{'b'}();
|
||||
$a->b['c']();
|
||||
|
||||
// array dereferencing
|
||||
@@ -87,20 +86,6 @@ array(
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
@@ -119,7 +104,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_FuncCall(
|
||||
name: Name(
|
||||
|
@@ -5,7 +5,6 @@ Object access
|
||||
// property fetch variations
|
||||
$a->b;
|
||||
$a->b['c'];
|
||||
$a->b{'c'};
|
||||
|
||||
// method call variations
|
||||
$a->b();
|
||||
@@ -15,7 +14,6 @@ $a->$b['c']();
|
||||
|
||||
// array dereferencing
|
||||
$a->b()['c'];
|
||||
$a->b(){'c'};
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
@@ -47,21 +45,6 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
@@ -76,7 +59,7 @@ array(
|
||||
0: // method call variations
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
@@ -88,7 +71,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
@@ -100,7 +83,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
@@ -119,7 +102,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
@@ -139,21 +122,4 @@ array(
|
||||
0: // array dereferencing
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_MethodCall(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@@ -5,7 +5,6 @@ Simple array access
|
||||
$a['b'];
|
||||
$a['b']['c'];
|
||||
$a[] = $b;
|
||||
$a{'b'};
|
||||
${$a}['b'];
|
||||
-----
|
||||
array(
|
||||
@@ -48,16 +47,6 @@ array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: b
|
||||
)
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: Expr_Variable(
|
||||
|
@@ -9,7 +9,6 @@ A::${'b'};
|
||||
|
||||
// array access
|
||||
A::$b['c'];
|
||||
A::$b{'c'};
|
||||
|
||||
// class name variations can be found in staticCall.test
|
||||
-----
|
||||
@@ -65,22 +64,7 @@ array(
|
||||
0: // array access
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_StaticPropertyFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: VarLikeIdentifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Nop(
|
||||
4: Stmt_Nop(
|
||||
comments: array(
|
||||
0: // class name variations can be found in staticCall.test
|
||||
)
|
||||
|
@@ -13,7 +13,6 @@ new A::$b();
|
||||
new $a->b();
|
||||
new $a->b->c();
|
||||
new $a->b['c']();
|
||||
new $a->b{'c'}();
|
||||
|
||||
// test regression introduces by new dereferencing syntax
|
||||
(new A);
|
||||
@@ -141,25 +140,6 @@ array(
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_ArrayDimFetch(
|
||||
var: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
name: a
|
||||
)
|
||||
name: Identifier(
|
||||
name: b
|
||||
)
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: c
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
9: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Name(
|
||||
name: A
|
||||
|
@@ -8,7 +8,6 @@ new A()::FOO;
|
||||
new A()::foo();
|
||||
new A()::$foo;
|
||||
new A()[0];
|
||||
new A(){0};
|
||||
new A()();
|
||||
|
||||
new class {}->foo;
|
||||
@@ -17,7 +16,6 @@ new class {}::FOO;
|
||||
new class {}::foo();
|
||||
new class {}::$foo;
|
||||
new class {}[0];
|
||||
new class {}{0};
|
||||
new class {}();
|
||||
-----
|
||||
array(
|
||||
@@ -110,20 +108,6 @@ array(
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_New(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_New(
|
||||
class: Name(
|
||||
@@ -136,7 +120,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_PropertyFetch(
|
||||
var: Expr_New(
|
||||
class: Stmt_Class(
|
||||
@@ -158,7 +142,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
9: Stmt_Expression(
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_New(
|
||||
class: Stmt_Class(
|
||||
@@ -182,7 +166,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
10: Stmt_Expression(
|
||||
9: Stmt_Expression(
|
||||
expr: Expr_ClassConstFetch(
|
||||
class: Expr_New(
|
||||
class: Stmt_Class(
|
||||
@@ -204,7 +188,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
11: Stmt_Expression(
|
||||
10: Stmt_Expression(
|
||||
expr: Expr_StaticCall(
|
||||
class: Expr_New(
|
||||
class: Stmt_Class(
|
||||
@@ -228,7 +212,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
12: Stmt_Expression(
|
||||
11: Stmt_Expression(
|
||||
expr: Expr_StaticPropertyFetch(
|
||||
class: Expr_New(
|
||||
class: Stmt_Class(
|
||||
@@ -250,51 +234,29 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
12: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
13: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
14: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_New(
|
||||
class: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: null
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
15: Stmt_Expression(
|
||||
expr: Expr_FuncCall(
|
||||
name: Expr_New(
|
||||
class: Stmt_Class(
|
||||
|
@@ -6,11 +6,9 @@ A->length;
|
||||
A->length();
|
||||
A[0];
|
||||
A[0][1][2];
|
||||
A{0};
|
||||
|
||||
A::B[0];
|
||||
A::B[0][1][2];
|
||||
A::B{0};
|
||||
A::B->length;
|
||||
A::B->length();
|
||||
A::B::C;
|
||||
@@ -83,18 +81,6 @@ array(
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: A
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -109,7 +95,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ArrayDimFetch(
|
||||
var: Expr_ArrayDimFetch(
|
||||
@@ -134,22 +120,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
name: A
|
||||
)
|
||||
name: Identifier(
|
||||
name: B
|
||||
)
|
||||
)
|
||||
dim: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
6: Stmt_Expression(
|
||||
expr: Expr_PropertyFetch(
|
||||
var: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -164,7 +135,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
9: Stmt_Expression(
|
||||
7: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -181,7 +152,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
10: Stmt_Expression(
|
||||
8: Stmt_Expression(
|
||||
expr: Expr_ClassConstFetch(
|
||||
class: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -196,7 +167,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
11: Stmt_Expression(
|
||||
9: Stmt_Expression(
|
||||
expr: Expr_StaticPropertyFetch(
|
||||
class: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -211,7 +182,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
12: Stmt_Expression(
|
||||
10: Stmt_Expression(
|
||||
expr: Expr_StaticCall(
|
||||
class: Expr_ClassConstFetch(
|
||||
class: Name(
|
||||
@@ -228,7 +199,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
13: Stmt_Expression(
|
||||
11: Stmt_Expression(
|
||||
expr: Expr_ArrayDimFetch(
|
||||
var: Scalar_MagicConst_Function(
|
||||
)
|
||||
@@ -237,7 +208,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
14: Stmt_Expression(
|
||||
12: Stmt_Expression(
|
||||
expr: Expr_PropertyFetch(
|
||||
var: Scalar_MagicConst_Function(
|
||||
)
|
||||
@@ -246,7 +217,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
15: Stmt_Expression(
|
||||
13: Stmt_Expression(
|
||||
expr: Expr_MethodCall(
|
||||
var: Expr_ConstFetch(
|
||||
name: Name(
|
||||
|
@@ -211,6 +211,8 @@ array(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
@@ -289,6 +291,8 @@ array(
|
||||
name: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
uses: array(
|
||||
|
@@ -3,7 +3,6 @@ UVS new expressions
|
||||
<?php
|
||||
new $className;
|
||||
new $array['className'];
|
||||
new $array{'className'};
|
||||
new $obj->className;
|
||||
new Test::$className;
|
||||
new $test::$className;
|
||||
@@ -34,20 +33,6 @@ array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_ArrayDimFetch(
|
||||
var: Expr_Variable(
|
||||
name: array
|
||||
)
|
||||
dim: Scalar_String(
|
||||
value: className
|
||||
)
|
||||
)
|
||||
args: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_PropertyFetch(
|
||||
var: Expr_Variable(
|
||||
@@ -61,7 +46,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
4: Stmt_Expression(
|
||||
3: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_StaticPropertyFetch(
|
||||
class: Name(
|
||||
@@ -75,7 +60,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Stmt_Expression(
|
||||
4: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_StaticPropertyFetch(
|
||||
class: Expr_Variable(
|
||||
@@ -89,7 +74,7 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
6: Stmt_Expression(
|
||||
5: Stmt_Expression(
|
||||
expr: Expr_New(
|
||||
class: Expr_StaticPropertyFetch(
|
||||
class: Expr_PropertyFetch(
|
||||
|
@@ -10,6 +10,7 @@ __LINE__;
|
||||
__METHOD__;
|
||||
__NAMESPACE__;
|
||||
__TRAIT__;
|
||||
__PROPERTY__;
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Expression(
|
||||
@@ -44,4 +45,8 @@ array(
|
||||
expr: Scalar_MagicConst_Trait(
|
||||
)
|
||||
)
|
||||
8: Stmt_Expression(
|
||||
expr: Scalar_MagicConst_Property(
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@@ -133,6 +133,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
5: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -147,6 +149,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
6: Stmt_ClassConst(
|
||||
attrGroups: array(
|
||||
|
@@ -159,6 +159,8 @@ array(
|
||||
name: param
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -189,6 +191,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@@ -102,6 +102,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
191
test/code/parser/stmt/class/asymmetric_visibility.test
Normal file
191
test/code/parser/stmt/class/asymmetric_visibility.test
Normal file
@@ -0,0 +1,191 @@
|
||||
Asymmetric visibility modifiers
|
||||
-----
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
protected private(set) $a;
|
||||
private public(set) $b;
|
||||
protected(set) $c;
|
||||
|
||||
public function __construct(
|
||||
protected private(set) $d,
|
||||
private public(set) $e,
|
||||
protected(set) $f,
|
||||
) {}
|
||||
}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED | PRIVATE_SET (514)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE | PUBLIC_SET (132)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED_SET (256)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: c
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: __construct
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED | PRIVATE_SET (514)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: d
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE | PUBLIC_SET (132)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: e
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED_SET (256)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: f
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
private(set) private(set) $x;
|
||||
private(set) public(set) $x;
|
||||
}
|
||||
-----
|
||||
Multiple access type modifiers are not allowed from 3:18 to 3:29
|
||||
Multiple access type modifiers are not allowed from 4:18 to 4:28
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE_SET (512)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC_SET | PRIVATE_SET (640)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: x
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@@ -37,6 +37,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -51,6 +53,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
|
@@ -28,6 +28,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -61,6 +63,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -94,6 +98,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -159,6 +165,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -247,69 +255,3 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php class B { abstract $b; }
|
||||
-----
|
||||
Properties cannot be declared abstract from 1:17 to 1:24
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: B
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: ABSTRACT (16)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php class A { final $a; }
|
||||
-----
|
||||
Properties cannot be declared final from 1:17 to 1:21
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: A
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: FINAL (32)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@@ -33,6 +33,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
|
@@ -36,6 +36,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -52,6 +54,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -70,6 +74,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -88,6 +94,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
638
test/code/parser/stmt/class/property_hooks.test
Normal file
638
test/code/parser/stmt/class/property_hooks.test
Normal file
@@ -0,0 +1,638 @@
|
||||
Property hooks
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
get { return 42; }
|
||||
set { echo $value; }
|
||||
}
|
||||
private $prop2 {
|
||||
get => 42;
|
||||
set => $value;
|
||||
}
|
||||
abstract $prop3 {
|
||||
&get;
|
||||
set;
|
||||
}
|
||||
public $prop4 {
|
||||
final get { return 42; }
|
||||
set(string $value) { }
|
||||
}
|
||||
}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: array(
|
||||
0: Stmt_Return(
|
||||
expr: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: set
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: array(
|
||||
0: Stmt_Echo(
|
||||
exprs: array(
|
||||
0: Expr_Variable(
|
||||
name: value
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE (4)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop2
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
)
|
||||
1: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: set
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Expr_Variable(
|
||||
name: value
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: ABSTRACT (16)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop3
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: true
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
1: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: set
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop4
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: FINAL (32)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: array(
|
||||
0: Stmt_Return(
|
||||
expr: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
1: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: set
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: Identifier(
|
||||
name: string
|
||||
)
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: value
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
body: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {}
|
||||
public function __construct(public $prop2 {}) {}
|
||||
}
|
||||
-----
|
||||
Property hook list cannot be empty from 3:18 to 3:18
|
||||
Property hook list cannot be empty from 4:47 to 4:47
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: __construct
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: prop2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
get() => 42;
|
||||
}
|
||||
}
|
||||
-----
|
||||
get hook must not have a parameter list from 4:12 to 4:12
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop { FOO => bar; }
|
||||
}
|
||||
-----
|
||||
Unknown hook "FOO", expected "get" or "set" from 3:20 to 3:22
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: FOO
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Expr_ConstFetch(
|
||||
name: Name(
|
||||
name: bar
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
public $prop {
|
||||
public public get;
|
||||
protected get;
|
||||
private get;
|
||||
abstract static get;
|
||||
readonly get;
|
||||
}
|
||||
}
|
||||
-----
|
||||
Cannot use the public modifier on a property hook from 4:9 to 4:14
|
||||
Multiple access type modifiers are not allowed from 4:16 to 4:21
|
||||
Cannot use the public modifier on a property hook from 4:16 to 4:21
|
||||
Cannot use the protected modifier on a property hook from 5:9 to 5:17
|
||||
Cannot use the private modifier on a property hook from 6:9 to 6:15
|
||||
Cannot use the abstract modifier on a property hook from 7:9 to 7:16
|
||||
Cannot use the static modifier on a property hook from 7:18 to 7:23
|
||||
Cannot use the readonly modifier on a property hook from 8:9 to 8:16
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
1: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED (2)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
2: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE (4)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
3: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: ABSTRACT | STATIC (24)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
4: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: READONLY (64)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test
|
||||
{
|
||||
|
||||
public $foo, $bar { get { return 42; } }
|
||||
|
||||
}
|
||||
-----
|
||||
Cannot use hooks when declaring multiple properties from 5:23 to 5:23
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: foo
|
||||
)
|
||||
default: null
|
||||
)
|
||||
1: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: bar
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: array(
|
||||
0: Stmt_Return(
|
||||
expr: Scalar_Int(
|
||||
value: 42
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
-----
|
||||
<?php
|
||||
class Test
|
||||
{
|
||||
|
||||
public $foo, $bar { }
|
||||
|
||||
}
|
||||
-----
|
||||
Cannot use hooks when declaring multiple properties from 5:23 to 5:23
|
||||
Property hook list cannot be empty from 5:23 to 5:23
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: foo
|
||||
)
|
||||
default: null
|
||||
)
|
||||
1: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: bar
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
89
test/code/parser/stmt/class/property_modifiers.test
Normal file
89
test/code/parser/stmt/class/property_modifiers.test
Normal file
@@ -0,0 +1,89 @@
|
||||
Property modifiers
|
||||
-----
|
||||
<?php
|
||||
class Test {
|
||||
final public $prop;
|
||||
abstract protected $prop;
|
||||
readonly $prop;
|
||||
private static $prop;
|
||||
}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Class(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
name: Identifier(
|
||||
name: Test
|
||||
)
|
||||
extends: null
|
||||
implements: array(
|
||||
)
|
||||
stmts: array(
|
||||
0: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC | FINAL (33)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PROTECTED | ABSTRACT (18)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: READONLY (64)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PRIVATE | STATIC (12)
|
||||
type: null
|
||||
props: array(
|
||||
0: PropertyItem(
|
||||
name: VarLikeIdentifier(
|
||||
name: prop
|
||||
)
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
@@ -8,6 +8,8 @@ class Point {
|
||||
protected array $y = [],
|
||||
private string $z = 'hello',
|
||||
public readonly int $a = 0,
|
||||
public $h { set => $value; },
|
||||
public $g = 1 { get => 2; },
|
||||
) {}
|
||||
}
|
||||
-----
|
||||
@@ -47,6 +49,8 @@ array(
|
||||
default: Scalar_Float(
|
||||
value: 0
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -64,6 +68,8 @@ array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -80,6 +86,8 @@ array(
|
||||
default: Scalar_String(
|
||||
value: hello
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -96,6 +104,66 @@ array(
|
||||
default: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: h
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: set
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Expr_Variable(
|
||||
name: value
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
5: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: PUBLIC (1)
|
||||
type: null
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: g
|
||||
)
|
||||
default: Scalar_Int(
|
||||
value: 1
|
||||
)
|
||||
hooks: array(
|
||||
0: PropertyHook(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: get
|
||||
)
|
||||
params: array(
|
||||
)
|
||||
body: Scalar_Int(
|
||||
value: 2
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -83,6 +83,8 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -97,6 +99,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -111,6 +115,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Stmt_ClassMethod(
|
||||
attrGroups: array(
|
||||
@@ -146,6 +152,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -25,6 +25,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -39,6 +41,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -53,6 +57,8 @@ array(
|
||||
name: c
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -67,6 +73,8 @@ array(
|
||||
name: d
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -81,6 +89,8 @@ array(
|
||||
name: e
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
5: Param(
|
||||
attrGroups: array(
|
||||
@@ -95,6 +105,8 @@ array(
|
||||
name: f
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
6: Param(
|
||||
attrGroups: array(
|
||||
@@ -109,6 +121,8 @@ array(
|
||||
name: g
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: Identifier(
|
||||
|
@@ -25,6 +25,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -50,6 +52,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -38,6 +38,8 @@ array(
|
||||
name: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -52,6 +54,8 @@ array(
|
||||
default: Scalar_String(
|
||||
value: foo
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -71,6 +75,8 @@ array(
|
||||
name: B
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -87,6 +93,8 @@ array(
|
||||
value: 1
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -103,6 +111,8 @@ array(
|
||||
value: 1
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
5: Param(
|
||||
attrGroups: array(
|
||||
@@ -118,6 +128,8 @@ array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
6: Param(
|
||||
attrGroups: array(
|
||||
@@ -133,6 +145,8 @@ array(
|
||||
items: array(
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
7: Param(
|
||||
attrGroups: array(
|
||||
@@ -156,6 +170,8 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
8: Param(
|
||||
attrGroups: array(
|
||||
@@ -189,6 +205,8 @@ array(
|
||||
)
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -57,6 +57,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Property(
|
||||
attrGroups: array(
|
||||
@@ -87,6 +89,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -132,6 +136,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: UnionType(
|
||||
|
90
test/code/parser/stmt/function/exit_die_function.test
Normal file
90
test/code/parser/stmt/function/exit_die_function.test
Normal file
@@ -0,0 +1,90 @@
|
||||
Declaring exit and die function stubs
|
||||
-----
|
||||
<?php
|
||||
|
||||
function exit(string|int $status = 0): never {}
|
||||
|
||||
function die(string|int $status = 0): never {}
|
||||
-----
|
||||
array(
|
||||
0: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: exit
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: UnionType(
|
||||
types: array(
|
||||
0: Identifier(
|
||||
name: string
|
||||
)
|
||||
1: Identifier(
|
||||
name: int
|
||||
)
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: status
|
||||
)
|
||||
default: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: Identifier(
|
||||
name: never
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
1: Stmt_Function(
|
||||
attrGroups: array(
|
||||
)
|
||||
byRef: false
|
||||
name: Identifier(
|
||||
name: die
|
||||
)
|
||||
params: array(
|
||||
0: Param(
|
||||
attrGroups: array(
|
||||
)
|
||||
flags: 0
|
||||
type: UnionType(
|
||||
types: array(
|
||||
0: Identifier(
|
||||
name: string
|
||||
)
|
||||
1: Identifier(
|
||||
name: int
|
||||
)
|
||||
)
|
||||
)
|
||||
byRef: false
|
||||
variadic: false
|
||||
var: Expr_Variable(
|
||||
name: status
|
||||
)
|
||||
default: Scalar_Int(
|
||||
value: 0
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: Identifier(
|
||||
name: never
|
||||
)
|
||||
stmts: array(
|
||||
)
|
||||
)
|
||||
)
|
@@ -42,6 +42,8 @@ array(
|
||||
default: null
|
||||
)
|
||||
)
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -73,6 +75,8 @@ array(
|
||||
name: a
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: IntersectionType(
|
||||
|
@@ -29,6 +29,8 @@ array(
|
||||
name: bar
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -45,6 +47,8 @@ array(
|
||||
name: foo
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: NullableType(
|
||||
|
@@ -25,6 +25,8 @@ array(
|
||||
name: bar
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -74,6 +76,8 @@ array(
|
||||
name: name
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -86,6 +90,8 @@ array(
|
||||
name: value
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
@@ -118,6 +124,8 @@ array(
|
||||
name: foo
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -24,6 +24,8 @@ array(
|
||||
name: b
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -38,6 +40,8 @@ array(
|
||||
name: c
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -52,6 +56,8 @@ array(
|
||||
name: d
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -66,6 +72,8 @@ array(
|
||||
name: f
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
)
|
||||
returnType: null
|
||||
|
@@ -34,6 +34,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -48,6 +50,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -62,6 +66,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -76,6 +82,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -90,6 +98,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -107,6 +117,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -124,6 +136,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -141,6 +155,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -158,6 +174,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -228,6 +246,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -242,6 +262,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -256,6 +278,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -270,6 +294,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -284,6 +310,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -301,6 +329,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -318,6 +348,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -335,6 +367,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -352,6 +386,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -422,6 +458,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -436,6 +474,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -450,6 +490,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -464,6 +506,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -478,6 +522,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -495,6 +541,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -512,6 +560,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -529,6 +579,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -546,6 +598,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -616,6 +670,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -630,6 +686,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -644,6 +702,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -658,6 +718,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -672,6 +734,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -689,6 +753,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -706,6 +772,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -723,6 +791,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -740,6 +810,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -810,6 +882,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -824,6 +898,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -838,6 +914,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -852,6 +930,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -866,6 +946,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -883,6 +965,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -900,6 +984,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -917,6 +1003,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -934,6 +1022,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -1004,6 +1094,8 @@ array(
|
||||
name: a1
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
1: Param(
|
||||
attrGroups: array(
|
||||
@@ -1018,6 +1110,8 @@ array(
|
||||
name: a2
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
2: Param(
|
||||
attrGroups: array(
|
||||
@@ -1032,6 +1126,8 @@ array(
|
||||
name: a3
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
3: Param(
|
||||
attrGroups: array(
|
||||
@@ -1046,6 +1142,8 @@ array(
|
||||
name: a4
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
)
|
||||
4: Param(
|
||||
attrGroups: array(
|
||||
@@ -1060,6 +1158,8 @@ array(
|
||||
name: a5
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.0
|
||||
)
|
||||
@@ -1077,6 +1177,8 @@ array(
|
||||
name: a6
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.1
|
||||
)
|
||||
@@ -1094,6 +1196,8 @@ array(
|
||||
name: a7
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 7.2
|
||||
)
|
||||
@@ -1111,6 +1215,8 @@ array(
|
||||
name: a8
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
@@ -1128,6 +1234,8 @@ array(
|
||||
name: a9
|
||||
)
|
||||
default: null
|
||||
hooks: array(
|
||||
)
|
||||
comments: array(
|
||||
0: // PHP 8.0
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user