diff --git a/Zend/tests/new_without_parentheses/anonymous_class_access.phpt b/Zend/tests/new_without_parentheses/anonymous_class_access.phpt new file mode 100644 index 0000000000000..326f6cd25392b --- /dev/null +++ b/Zend/tests/new_without_parentheses/anonymous_class_access.phpt @@ -0,0 +1,64 @@ +--TEST-- +Immediate access on new anonymous class +--FILE-- +property; + +echo new class { + public static $property = 'static property' . PHP_EOL; +}::$property; + +new class { + public function method() { echo 'method' . PHP_EOL; } +}->method(); + +new class { + public static function method() { echo 'static method' . PHP_EOL; } +}::method(); + +new class { + public function __invoke() { echo '__invoke' . PHP_EOL; } +}(); + +new class () implements ArrayAccess { + public function offsetExists(mixed $offset): bool { return true; } + + public function offsetGet(mixed $offset): mixed { echo 'offsetGet' . PHP_EOL; return null; } + + public function offsetSet(mixed $offset, mixed $value): void {} + + public function offsetUnset(mixed $offset): void {} +}['key']; + +isset(new class () implements ArrayAccess { + public function offsetExists(mixed $offset): bool { echo 'offsetExists' . PHP_EOL; return true; } + + public function offsetGet(mixed $offset): mixed { return null; } + + public function offsetSet(mixed $offset, mixed $value): void {} + + public function offsetUnset(mixed $offset): void {} +}['key']); + +?> +--EXPECT-- +constant +constant +property +static property +method +static method +__invoke +offsetGet +offsetExists diff --git a/Zend/tests/new_without_parentheses/assign_to_new.phpt b/Zend/tests/new_without_parentheses/assign_to_new.phpt new file mode 100644 index 0000000000000..bee87457a1e3c --- /dev/null +++ b/Zend/tests/new_without_parentheses/assign_to_new.phpt @@ -0,0 +1,10 @@ +--TEST-- +Cannot assign to new expression +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token "=" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/garbage_collection.phpt b/Zend/tests/new_without_parentheses/garbage_collection.phpt new file mode 100644 index 0000000000000..4b7c7733a5e59 --- /dev/null +++ b/Zend/tests/new_without_parentheses/garbage_collection.phpt @@ -0,0 +1,26 @@ +--TEST-- +Object instantiated without parentheses is collected +--FILE-- +test(); +echo 'code after' . PHP_EOL; + +?> +--EXPECT-- +called +collected +code after diff --git a/Zend/tests/new_without_parentheses/new_class_vs_function_with_same_name.phpt b/Zend/tests/new_without_parentheses/new_class_vs_function_with_same_name.phpt new file mode 100644 index 0000000000000..cd3161e15b939 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_class_vs_function_with_same_name.phpt @@ -0,0 +1,25 @@ +--TEST-- +A function and a class with the same name work as expected +--FILE-- + +--EXPECT-- +Another +object(Something)#1 (0) { +} +object(Another)#1 (0) { +} diff --git a/Zend/tests/new_without_parentheses/new_with_ctor_arguments_parentheses.phpt b/Zend/tests/new_without_parentheses/new_with_ctor_arguments_parentheses.phpt new file mode 100644 index 0000000000000..10f35957e00ed --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_with_ctor_arguments_parentheses.phpt @@ -0,0 +1,111 @@ +--TEST-- +Immediate access on new object with constructor arguments' parentheses +--FILE-- +property; +echo new $class()->property; +echo new (trim(' A '))()->property; + +echo new A()::$staticProperty; +echo new $class()::$staticProperty; +echo new (trim(' A '))()::$staticProperty; + +new A()(); +new $class()(); +new (trim(' A '))()(); + +new A()->method(); +new $class()->method(); +new (trim(' A '))()->method(); + +new A()::staticMethod(); +new $class()::staticMethod(); +new (trim(' A '))()::staticMethod(); + +new A()['key']; +new $class()['key']; +new (trim(' A '))()['key']; + +isset(new A()['key']); +isset(new $class()['key']); +isset(new (trim(' A '))()['key']); + +?> +--EXPECT-- +constant +constant +constant +constant +constant +constant +property +property +property +static property +static property +static property +__invoke +__invoke +__invoke +method +method +method +static method +static method +static method +offsetGet +offsetGet +offsetGet +offsetExists +offsetExists +offsetExists diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_array_access.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_array_access.phpt new file mode 100644 index 0000000000000..5d93ea1f34ac6 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_array_access.phpt @@ -0,0 +1,14 @@ +--TEST-- +Immediate array access on new object without constructor parentheses +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token "[", expecting "," or ";" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_constant.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_constant.phpt new file mode 100644 index 0000000000000..27b9697da1793 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_constant.phpt @@ -0,0 +1,15 @@ +--TEST-- +Immediate constant access on new object without constructor parentheses +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected identifier "C", expecting variable or "$" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_method.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_method.phpt new file mode 100644 index 0000000000000..23fe24676d648 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_method.phpt @@ -0,0 +1,18 @@ +--TEST-- +Immediate method call on new object without constructor parentheses +--FILE-- +test(); + +?> +--EXPECTF-- +Parse error: syntax error, unexpected token "->" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_property.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_property.phpt new file mode 100644 index 0000000000000..6b1827983b090 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_property.phpt @@ -0,0 +1,15 @@ +--TEST-- +Immediate property access on new object without constructor parentheses +--FILE-- +prop; + +?> +--EXPECTF-- +Parse error: syntax error, unexpected token "->", expecting "," or ";" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_method.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_method.phpt new file mode 100644 index 0000000000000..ee422d90e720f --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_method.phpt @@ -0,0 +1,18 @@ +--TEST-- +Immediate static method call on new object without constructor parentheses +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected identifier "test", expecting variable or "$" in %s on line %d diff --git a/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_property.phpt b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_property.phpt new file mode 100644 index 0000000000000..4e309071c9fc4 --- /dev/null +++ b/Zend/tests/new_without_parentheses/new_without_ctor_arguments_parentheses_static_property.phpt @@ -0,0 +1,20 @@ +--TEST-- +Immediate static property access on new object without constructor parentheses +--FILE-- + +--EXPECT-- +object(B)#1 (0) { +} diff --git a/Zend/tests/new_without_parentheses/unset_new.phpt b/Zend/tests/new_without_parentheses/unset_new.phpt new file mode 100644 index 0000000000000..3d46d1ca3faa4 --- /dev/null +++ b/Zend/tests/new_without_parentheses/unset_new.phpt @@ -0,0 +1,10 @@ +--TEST-- +Cannot unset new expression +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token ")", expecting "->" or "?->" or "{" or "[" in %s on line %d diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 6e882f922f374..748c8a8862791 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -255,7 +255,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type extends_from parameter optional_type_without_static argument global_var %type static_var class_statement trait_adaptation trait_precedence trait_alias %type absolute_trait_method_reference trait_method_reference property echo_expr -%type new_expr anonymous_class class_name class_name_reference simple_variable +%type new_dereferenceable new_non_dereferenceable anonymous_class class_name class_name_reference simple_variable %type internal_functions_in_yacc %type exit_expr scalar backticks_expr lexical_var function_call member_name property_name %type variable_class_name dereferenceable_scalar constant class_constant @@ -1123,8 +1123,8 @@ anonymous_class: } ; -new_expr: - T_NEW class_name_reference ctor_arguments +new_dereferenceable: + T_NEW class_name_reference argument_list { $$ = zend_ast_create(ZEND_AST_NEW, $2, $3); } | T_NEW anonymous_class { $$ = $2; } @@ -1132,6 +1132,11 @@ new_expr: { zend_ast_with_attributes($3->child[0], $2); $$ = $3; } ; +new_non_dereferenceable: + T_NEW class_name_reference + { $$ = zend_ast_create(ZEND_AST_NEW, $2, zend_ast_create_list(0, ZEND_AST_ARG_LIST)); } +; + expr: variable { $$ = $1; } @@ -1225,7 +1230,8 @@ expr: $$ = $2; if ($$->kind == ZEND_AST_CONDITIONAL) $$->attr = ZEND_PARENTHESIZED_CONDITIONAL; } - | new_expr { $$ = $1; } + | new_dereferenceable { $$ = $1; } + | new_non_dereferenceable { $$ = $1; } | expr '?' expr ':' expr { $$ = zend_ast_create(ZEND_AST_CONDITIONAL, $1, $3, $5); } | expr '?' ':' expr @@ -1418,6 +1424,7 @@ fully_dereferenceable: | '(' expr ')' { $$ = $2; } | dereferenceable_scalar { $$ = $1; } | class_constant { $$ = $1; } + | new_dereferenceable { $$ = $1; } ; array_object_dereferenceable: @@ -1429,6 +1436,7 @@ callable_expr: callable_variable { $$ = $1; } | '(' expr ')' { $$ = $2; } | dereferenceable_scalar { $$ = $1; } + | new_dereferenceable { $$ = $1; } ; callable_variable: