Skip to content

Treat namespaced names as single token, allow using reserved class names #5720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Zend/tests/attributes/018_variable_attribute_name.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ class A {}

?>
--EXPECTF--
Parse error: syntax error, unexpected '$x' (T_VARIABLE), expecting identifier (T_STRING) or static (T_STATIC) or namespace (T_NAMESPACE) or \\ (T_NS_SEPARATOR) in %s on line %d
Parse error: syntax error, unexpected '$x' (T_VARIABLE) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/bug43343.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ $foo = 'bar';
var_dump(new namespace::$foo);
?>
--EXPECTF--
Parse error: %s error%sexpecting%sT_NS_SEPARATOR%sin %sbug43343.php on line 5
Parse error: syntax error, unexpected 'namespace' (T_NAMESPACE) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/bug55086.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace N2 {
echo $a->hello(), PHP_EOL;
echo $a->foo(), PHP_EOL;
try {
} catch(namespace \Foo $e)
} catch (namespace\Foo $e)
{
}
}
Expand Down
6 changes: 3 additions & 3 deletions Zend/tests/grammar/regression_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ class Obj
function return(){} // valid
}

function echo(){} // not valid
--EXPECTF--
Parse error: syntax error, unexpected 'echo' (T_ECHO), expecting %s in %s on line 9
function echo(){} // valid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe an error like "Can not redeclare intrinsic PHP construct echo..." makes more sense here? Same for exit, die and print ?

--EXPECT--

6 changes: 3 additions & 3 deletions Zend/tests/grammar/regression_005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ class Obj
const return = 'yep';
}

const return = 'nope';
--EXPECTF--
Parse error: syntax error, unexpected 'return' (T_RETURN), expecting identifier (T_STRING) in %s on line 8
const return = 'yep';
--EXPECT--

7 changes: 5 additions & 2 deletions Zend/tests/grammar/regression_010.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ Test to check regressions on T_IMPLEMENTS followed by a T_NS_SEPARATOR

interface A{}

// No longer considered legal in PHP 8.
class B implements\A {}

echo "Done", PHP_EOL;
--EXPECT--
Done

?>
--EXPECTF--
Parse error: syntax error, unexpected 'implements\A' (T_NAME_QUALIFIED), expecting '{' in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/lsb_008.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ ZE2 Late Static Binding class name "static"
class static {
}
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/lsb_009.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ ZE2 Late Static Binding interface name "static"
interface static {
}
--EXPECTF--
Parse error: %s error,%sexpecting %s in %s on line %d
Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d
10 changes: 10 additions & 0 deletions Zend/tests/namespaced_name_whitespace.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--TEST--
Whitespace between namespace separators is no longer allowed
--FILE--
<?php

Foo \ Bar \ Baz;

?>
--EXPECTF--
Parse error: syntax error, unexpected '\' (T_NS_SEPARATOR) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/ns_096.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ use Foo\Bar\{\Baz};

?>
--EXPECTF--
Parse error: syntax error, unexpected '\' (T_NS_SEPARATOR), expecting identifier (T_STRING) or function (T_FUNCTION) or const (T_CONST) in %s on line 3
Parse error: syntax error, unexpected '\Baz' (T_NAME_FULLY_QUALIFIED), expecting identifier (T_STRING) or namespaced name (T_NAME_QUALIFIED) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/ns_trailing_comma_error_01.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Group use declarations mustn't be empty
use Baz\{};
?>
--EXPECTF--
Parse error: syntax error, unexpected '}', expecting identifier (T_STRING) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
Parse error: syntax error, unexpected '}', expecting identifier (T_STRING) or namespaced name (T_NAME_QUALIFIED) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/ns_trailing_comma_error_02.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Group use declarations mustn't contain just a comma
use Baz\{,};
?>
--EXPECTF--
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) or namespaced name (T_NAME_QUALIFIED) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/ns_trailing_comma_error_04.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Group use declarations mustn't begin with a comma
use Baz\{,Foo};
?>
--EXPECTF--
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) or namespaced name (T_NAME_QUALIFIED) or function (T_FUNCTION) or const (T_CONST) in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/ns_trailing_comma_error_07.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Unmixed group use declarations mustn't begin with a comma
use function Baz\{,Foo};
?>
--EXPECTF--
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) in %s on line %d
Parse error: syntax error, unexpected ',', expecting identifier (T_STRING) or namespaced name (T_NAME_QUALIFIED) in %s on line %d
47 changes: 47 additions & 0 deletions Zend/tests/reserved_namespaced_names.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
--TEST--
Can declare classes with reserved name
--FILE--
<?php

namespace FooBar {
class List {}
function list() { return []; }
const LIST = [];

class Test {}
}

namespace BarFoo {
use FooBar\List as MyList;
use function FooBar\list as get_list;
use const FooBar\LIST as THE_LIST;
use /* namespace */ FooBar as List;

var_dump(new \FooBar\List);
var_dump(new MyList);

var_dump(\FooBar\list());
var_dump(get_list());

var_dump(\FooBar\LIST);
var_dump(THE_LIST);

var_dump(new List\Test);
}

?>
--EXPECT--
object(FooBar\List)#1 (0) {
}
object(FooBar\List)#1 (0) {
}
array(0) {
}
array(0) {
}
array(0) {
}
array(0) {
}
object(FooBar\Test)#1 (0) {
}
58 changes: 31 additions & 27 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token <ast> T_LNUMBER "integer number (T_LNUMBER)"
%token <ast> T_DNUMBER "floating-point number (T_DNUMBER)"
%token <ast> T_STRING "identifier (T_STRING)"
%token <ast> T_NAME_FULLY_QUALIFIED "fully qualified name (T_NAME_FULLY_QUALIFIED)"
%token <ast> T_NAME_RELATIVE "namespace-relative name (T_NAME_RELATIVE)"
%token <ast> T_NAME_QUALIFIED "namespaced name (T_NAME_QUALIFIED)"
%token <ast> T_VARIABLE "variable (T_VARIABLE)"
%token <ast> T_INLINE_HTML
%token <ast> T_ENCAPSED_AND_WHITESPACE "quoted-string and whitespace (T_ENCAPSED_AND_WHITESPACE)"
Expand Down Expand Up @@ -230,7 +233,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token T_ERROR

%type <ast> top_statement namespace_name name statement function_declaration_statement
%type <ast> class_declaration_statement trait_declaration_statement
%type <ast> class_declaration_statement trait_declaration_statement legacy_namespace_name
%type <ast> interface_declaration_statement interface_extends_list
%type <ast> group_use_declaration inline_use_declarations inline_use_declaration
%type <ast> mixed_group_use_declaration use_declaration unprefixed_use_declaration
Expand All @@ -252,7 +255,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list
%type <ast> implements_list case_list if_stmt_without_else
%type <ast> non_empty_parameter_list argument_list non_empty_argument_list property_list
%type <ast> class_const_list class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs
%type <ast> class_const_list class_name_list trait_adaptations method_body non_empty_for_exprs
%type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars
%type <ast> lexical_var_list encaps_list
%type <ast> array_pair non_empty_array_pair_list array_pair_list possible_array_pair
Expand Down Expand Up @@ -308,13 +311,20 @@ top_statement_list:

namespace_name:
T_STRING { $$ = $1; }
| namespace_name T_NS_SEPARATOR T_STRING { $$ = zend_ast_append_str($1, $3); }
| T_NAME_QUALIFIED { $$ = $1; }
;

/* Some places allow using a leading backslash before a namespace name, because PHP. */
legacy_namespace_name:
namespace_name { $$ = $1; }
| T_NAME_FULLY_QUALIFIED { $$ = $1; }
;

name:
namespace_name { $$ = $1; $$->attr = ZEND_NAME_NOT_FQ; }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$ = $3; $$->attr = ZEND_NAME_RELATIVE; }
| T_NS_SEPARATOR namespace_name { $$ = $2; $$->attr = ZEND_NAME_FQ; }
T_STRING { $$ = $1; $$->attr = ZEND_NAME_NOT_FQ; }
| T_NAME_QUALIFIED { $$ = $1; $$->attr = ZEND_NAME_NOT_FQ; }
| T_NAME_FULLY_QUALIFIED { $$ = $1; $$->attr = ZEND_NAME_FQ; }
| T_NAME_RELATIVE { $$ = $1; $$->attr = ZEND_NAME_RELATIVE; }
;

attribute_arguments:
Expand Down Expand Up @@ -379,17 +389,13 @@ use_type:
;

group_use_declaration:
namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations possible_comma '}'
legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations possible_comma '}'
{ $$ = zend_ast_create(ZEND_AST_GROUP_USE, $1, $4); }
| T_NS_SEPARATOR namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations possible_comma '}'
{ $$ = zend_ast_create(ZEND_AST_GROUP_USE, $2, $5); }
;

mixed_group_use_declaration:
namespace_name T_NS_SEPARATOR '{' inline_use_declarations possible_comma '}'
legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations possible_comma '}'
{ $$ = zend_ast_create(ZEND_AST_GROUP_USE, $1, $4);}
| T_NS_SEPARATOR namespace_name T_NS_SEPARATOR '{' inline_use_declarations possible_comma '}'
{ $$ = zend_ast_create(ZEND_AST_GROUP_USE, $2, $5); }
;

possible_comma:
Expand Down Expand Up @@ -426,13 +432,15 @@ inline_use_declaration:
unprefixed_use_declaration:
namespace_name
{ $$ = zend_ast_create(ZEND_AST_USE_ELEM, $1, NULL); }
| namespace_name T_AS T_STRING
| namespace_name T_AS identifier
{ $$ = zend_ast_create(ZEND_AST_USE_ELEM, $1, $3); }
;

use_declaration:
unprefixed_use_declaration { $$ = $1; }
| T_NS_SEPARATOR unprefixed_use_declaration { $$ = $2; }
legacy_namespace_name
{ $$ = zend_ast_create(ZEND_AST_USE_ELEM, $1, NULL); }
| legacy_namespace_name T_AS identifier
{ $$ = zend_ast_create(ZEND_AST_USE_ELEM, $1, $3); }
;

const_list:
Expand Down Expand Up @@ -527,7 +535,7 @@ unset_variable:
;

function_declaration_statement:
function returns_ref T_STRING backup_doc_comment '(' parameter_list ')' return_type
function returns_ref identifier backup_doc_comment '(' parameter_list ')' return_type
backup_fn_flags '{' inner_statement_list '}' backup_fn_flags
{ $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2 | $13, $1, $4,
zend_ast_get_str($3), $6, NULL, $11, $8, NULL); CG(extra_fn_flags) = $9; }
Expand All @@ -545,10 +553,10 @@ is_variadic:

class_declaration_statement:
class_modifiers T_CLASS { $<num>$ = CG(zend_lineno); }
T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}'
identifier extends_from implements_list backup_doc_comment '{' class_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $<num>3, $7, zend_ast_get_str($4), $5, $6, $9, NULL, NULL); }
| T_CLASS { $<num>$ = CG(zend_lineno); }
T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}'
identifier extends_from implements_list backup_doc_comment '{' class_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $<num>2, $6, zend_ast_get_str($3), $4, $5, $8, NULL, NULL); }
;

Expand All @@ -565,13 +573,13 @@ class_modifier:

trait_declaration_statement:
T_TRAIT { $<num>$ = CG(zend_lineno); }
T_STRING backup_doc_comment '{' class_statement_list '}'
identifier backup_doc_comment '{' class_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $<num>2, $4, zend_ast_get_str($3), NULL, NULL, $6, NULL, NULL); }
;

interface_declaration_statement:
T_INTERFACE { $<num>$ = CG(zend_lineno); }
T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}'
identifier interface_extends_list backup_doc_comment '{' class_statement_list '}'
{ $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $<num>2, $5, zend_ast_get_str($3), NULL, $4, $7, NULL, NULL); }
;

Expand Down Expand Up @@ -915,16 +923,12 @@ property:
;

class_const_list:
class_const_list ',' class_const_decl { $$ = zend_ast_list_add($1, $3); }
| class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); }
;

class_const_decl:
identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
class_const_list ',' const_decl { $$ = zend_ast_list_add($1, $3); }
| const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); }
;

const_decl:
T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
;

echo_expr_list:
Expand Down
20 changes: 16 additions & 4 deletions Zend/zend_language_scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -1586,10 +1586,6 @@ NEWLINE ("\r"|"\n"|"\r\n")
RETURN_TOKEN(T_PAAMAYIM_NEKUDOTAYIM);
}

<ST_IN_SCRIPTING>"\\" {
RETURN_TOKEN(T_NS_SEPARATOR);
}

<ST_IN_SCRIPTING>"..." {
RETURN_TOKEN(T_ELLIPSIS);
}
Expand Down Expand Up @@ -2277,6 +2273,22 @@ inline_char_handler:
RETURN_TOKEN_WITH_VAL(T_ENCAPSED_AND_WHITESPACE);
}

<ST_IN_SCRIPTING>"namespace"("\\"{LABEL})+ {
RETURN_TOKEN_WITH_STR(T_NAME_RELATIVE, sizeof("namespace\\") - 1);
}

<ST_IN_SCRIPTING>{LABEL}("\\"{LABEL})+ {
RETURN_TOKEN_WITH_STR(T_NAME_QUALIFIED, 0);
}

<ST_IN_SCRIPTING>"\\"{LABEL}("\\"{LABEL})* {
RETURN_TOKEN_WITH_STR(T_NAME_FULLY_QUALIFIED, 1);
}

<ST_IN_SCRIPTING>"\\" {
RETURN_TOKEN(T_NS_SEPARATOR);
}

<ST_IN_SCRIPTING,ST_VAR_OFFSET>{LABEL} {
RETURN_TOKEN_WITH_STR(T_STRING, 0);
}
Expand Down