summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UPGRADING9
-rw-r--r--Zend/tests/attributes/019_variable_attribute_name.phpt2
-rw-r--r--Zend/tests/bug43343.phpt2
-rw-r--r--Zend/tests/bug55086.phpt2
-rw-r--r--Zend/tests/grammar/regression_010.phpt7
-rw-r--r--Zend/tests/namespace_name_namespace.phpt10
-rw-r--r--Zend/tests/namespace_name_namespace_start.phpt10
-rw-r--r--Zend/tests/namespace_name_reserved_keywords.phpt37
-rw-r--r--Zend/tests/namespaced_name_whitespace.phpt10
-rw-r--r--Zend/tests/ns_096.phpt2
-rw-r--r--Zend/tests/ns_trailing_comma_error_01.phpt2
-rw-r--r--Zend/tests/ns_trailing_comma_error_02.phpt2
-rw-r--r--Zend/tests/ns_trailing_comma_error_04.phpt2
-rw-r--r--Zend/tests/ns_trailing_comma_error_07.phpt2
-rw-r--r--Zend/tests/special_name_error1.phpt10
-rw-r--r--Zend/zend_compile.c2
-rw-r--r--Zend/zend_language_parser.y47
-rw-r--r--Zend/zend_language_scanner.l20
-rw-r--r--ext/tokenizer/tests/namespaced_names.phpt39
-rw-r--r--ext/tokenizer/tokenizer_data.c6
20 files changed, 182 insertions, 41 deletions
diff --git a/UPGRADING b/UPGRADING
index eed08ad8ef..8c75319664 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -204,6 +204,10 @@ PHP 8.0 UPGRADE NOTES
numbers and numeric strings continue to work as before. Notably, this means
that `0 == "not-a-number"` is considered false now.
RFC: https://wiki.php.net/rfc/string_to_number_comparison
+ . Namespaced names can no longer contain whitespace: While `Foo\Bar` will be
+ recognized as a namespaced name, `Foo \ Bar` will not. Conversely, reserved
+ keywords are now permitted as namespace segments.
+ RFC: https://wiki.php.net/rfc/namespaced_names_as_token
- COM:
. Removed the ability to import case-insensitive constants from type
@@ -509,6 +513,11 @@ PHP 8.0 UPGRADE NOTES
instead be part of a following T_WHITESPACE token. It should be noted that
T_COMMENT is not always followed by whitespace, it may also be followed by
T_CLOSE_TAG or end-of-file.
+ . Namespaced names are now represented using the T_NAME_QUALIFIED (Foo\Bar),
+ T_NAME_FULLY_QUALIFIED (\Foo\Bar) and T_NAME_RELATIVE (namespace\Foo\Bar)
+ tokens. T_NS_SEPARATOR is only used for standalone namespace separators,
+ and only syntactially valid in conjunction with group use declarations.
+ RFC: https://wiki.php.net/rfc/namespaced_names_as_token
- XML:
. xml_parser_create(_ns) will now return an XmlParser object rather than a
diff --git a/Zend/tests/attributes/019_variable_attribute_name.phpt b/Zend/tests/attributes/019_variable_attribute_name.phpt
index 2710abbed9..a259c06f3f 100644
--- a/Zend/tests/attributes/019_variable_attribute_name.phpt
+++ b/Zend/tests/attributes/019_variable_attribute_name.phpt
@@ -8,4 +8,4 @@ class A {}
?>
--EXPECTF--
-Parse error: syntax error, unexpected variable "$x", expecting identifier or "static" or "namespace" or "\" in %s on line %d
+Parse error: syntax error, unexpected variable "$x" in %s on line %d
diff --git a/Zend/tests/bug43343.phpt b/Zend/tests/bug43343.phpt
index db72fe98ec..c277ccccdd 100644
--- a/Zend/tests/bug43343.phpt
+++ b/Zend/tests/bug43343.phpt
@@ -8,4 +8,4 @@ $foo = 'bar';
var_dump(new namespace::$foo);
?>
--EXPECTF--
-Parse error: %s error%sexpecting%s"\"%sin %sbug43343.php on line 5
+Parse error: syntax error, unexpected token "namespace" in %s on line %d
diff --git a/Zend/tests/bug55086.phpt b/Zend/tests/bug55086.phpt
index 9a5c747b9f..10be0d1ef5 100644
--- a/Zend/tests/bug55086.phpt
+++ b/Zend/tests/bug55086.phpt
@@ -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)
{
}
}
diff --git a/Zend/tests/grammar/regression_010.phpt b/Zend/tests/grammar/regression_010.phpt
index e5e65e3a85..0e535aad6b 100644
--- a/Zend/tests/grammar/regression_010.phpt
+++ b/Zend/tests/grammar/regression_010.phpt
@@ -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 namespaced name "implements\A", expecting "{" in %s on line %d
diff --git a/Zend/tests/namespace_name_namespace.phpt b/Zend/tests/namespace_name_namespace.phpt
new file mode 100644
index 0000000000..311705ab2e
--- /dev/null
+++ b/Zend/tests/namespace_name_namespace.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Cannot use "namespace" as namespace name, due to conflict with ns-relative names
+--FILE--
+<?php
+
+namespace NAMEspace;
+
+?>
+--EXPECTF--
+Fatal error: Cannot use 'NAMEspace' as namespace name in %s on line %d
diff --git a/Zend/tests/namespace_name_namespace_start.phpt b/Zend/tests/namespace_name_namespace_start.phpt
new file mode 100644
index 0000000000..bf812fed79
--- /dev/null
+++ b/Zend/tests/namespace_name_namespace_start.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Cannot use "namespace\xyz" as namespace name, due to conflict with ns-relative names
+--FILE--
+<?php
+
+namespace NAMEspace\xyz;
+
+?>
+--EXPECTF--
+Parse error: syntax error, unexpected namespace-relative name "NAMEspace\xyz", expecting "{" in %s on line %d
diff --git a/Zend/tests/namespace_name_reserved_keywords.phpt b/Zend/tests/namespace_name_reserved_keywords.phpt
new file mode 100644
index 0000000000..9374ef6a63
--- /dev/null
+++ b/Zend/tests/namespace_name_reserved_keywords.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Reserved keywords in namespace name
+--FILE--
+<?php
+
+namespace iter\fn {
+ function test() {
+ echo __FUNCTION__, "\n";
+ }
+}
+
+namespace fn {
+ function test() {
+ echo __FUNCTION__, "\n";
+ }
+}
+
+namespace self {
+ function test() {
+ echo __FUNCTION__, "\n";
+ }
+}
+
+namespace {
+ use iter\fn;
+ use function fn\test as test2;
+ use function self\test as test3;
+ fn\test();
+ test2();
+ test3();
+}
+
+?>
+--EXPECT--
+iter\fn\test
+fn\test
+self\test
diff --git a/Zend/tests/namespaced_name_whitespace.phpt b/Zend/tests/namespaced_name_whitespace.phpt
new file mode 100644
index 0000000000..746b3298e9
--- /dev/null
+++ b/Zend/tests/namespaced_name_whitespace.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Whitespace between namespace separators is no longer allowed
+--FILE--
+<?php
+
+Foo \ Bar \ Baz;
+
+?>
+--EXPECTF--
+Parse error: syntax error, unexpected token "\" in %s on line %d
diff --git a/Zend/tests/ns_096.phpt b/Zend/tests/ns_096.phpt
index f72e37f7d3..03b09047ff 100644
--- a/Zend/tests/ns_096.phpt
+++ b/Zend/tests/ns_096.phpt
@@ -7,4 +7,4 @@ use Foo\Bar\{\Baz};
?>
--EXPECTF--
-Parse error: syntax error, unexpected token "\", expecting identifier or "function" or "const" in %s on line %d
+Parse error: syntax error, unexpected fully qualified name "\Baz", expecting identifier or namespaced name or "function" or "const" in %s on line %d
diff --git a/Zend/tests/ns_trailing_comma_error_01.phpt b/Zend/tests/ns_trailing_comma_error_01.phpt
index 7b9c5177bf..f8fa5dbf12 100644
--- a/Zend/tests/ns_trailing_comma_error_01.phpt
+++ b/Zend/tests/ns_trailing_comma_error_01.phpt
@@ -5,4 +5,4 @@ Group use declarations mustn't be empty
use Baz\{};
?>
--EXPECTF--
-Parse error: syntax error, unexpected token "}", expecting identifier or "function" or "const" in %s on line %d
+Parse error: syntax error, unexpected token "}", expecting identifier or namespaced name or "function" or "const" in %s on line %d
diff --git a/Zend/tests/ns_trailing_comma_error_02.phpt b/Zend/tests/ns_trailing_comma_error_02.phpt
index 91b70d3bd6..f73ffe748d 100644
--- a/Zend/tests/ns_trailing_comma_error_02.phpt
+++ b/Zend/tests/ns_trailing_comma_error_02.phpt
@@ -5,4 +5,4 @@ Group use declarations mustn't contain just a comma
use Baz\{,};
?>
--EXPECTF--
-Parse error: syntax error, unexpected token ",", expecting identifier or "function" or "const" in %s on line %d
+Parse error: syntax error, unexpected token ",", expecting identifier or namespaced name or "function" or "const" in %s on line %d
diff --git a/Zend/tests/ns_trailing_comma_error_04.phpt b/Zend/tests/ns_trailing_comma_error_04.phpt
index 2712c5aa11..18bbea745a 100644
--- a/Zend/tests/ns_trailing_comma_error_04.phpt
+++ b/Zend/tests/ns_trailing_comma_error_04.phpt
@@ -5,4 +5,4 @@ Group use declarations mustn't begin with a comma
use Baz\{,Foo};
?>
--EXPECTF--
-Parse error: syntax error, unexpected token ",", expecting identifier or "function" or "const" in %s on line %d
+Parse error: syntax error, unexpected token ",", expecting identifier or namespaced name or "function" or "const" in %s on line %d
diff --git a/Zend/tests/ns_trailing_comma_error_07.phpt b/Zend/tests/ns_trailing_comma_error_07.phpt
index 742d809bbc..c7798da8f0 100644
--- a/Zend/tests/ns_trailing_comma_error_07.phpt
+++ b/Zend/tests/ns_trailing_comma_error_07.phpt
@@ -5,4 +5,4 @@ Unmixed group use declarations mustn't begin with a comma
use function Baz\{,Foo};
?>
--EXPECTF--
-Parse error: syntax error, unexpected token ",", expecting identifier in %s on line %d
+Parse error: syntax error, unexpected token ",", expecting identifier or namespaced name in %s on line %d
diff --git a/Zend/tests/special_name_error1.phpt b/Zend/tests/special_name_error1.phpt
deleted file mode 100644
index 63bf5a63fd..0000000000
--- a/Zend/tests/special_name_error1.phpt
+++ /dev/null
@@ -1,10 +0,0 @@
---TEST--
-Cannot use special class name as namespace
---FILE--
-<?php
-
-namespace self;
-
-?>
---EXPECTF--
-Fatal error: Cannot use 'self' as namespace name in %s on line %d
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index aafe582f9f..d555297c17 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -7432,7 +7432,7 @@ void zend_compile_namespace(zend_ast *ast) /* {{{ */
if (name_ast) {
name = zend_ast_get_str(name_ast);
- if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
+ if (zend_string_equals_literal_ci(name, "namespace")) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", ZSTR_VAL(name));
}
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 891624c461..acb7a3d954 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -89,6 +89,9 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token <ast> T_LNUMBER "integer"
%token <ast> T_DNUMBER "floating-point number"
%token <ast> T_STRING "identifier"
+%token <ast> T_NAME_FULLY_QUALIFIED "fully qualified name"
+%token <ast> T_NAME_RELATIVE "namespace-relative name"
+%token <ast> T_NAME_QUALIFIED "namespaced name"
%token <ast> T_VARIABLE "variable"
%token <ast> T_INLINE_HTML
%token <ast> T_ENCAPSED_AND_WHITESPACE "string content"
@@ -231,7 +234,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
@@ -261,7 +264,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> identifier type_expr_without_static union_type_without_static
%type <ast> inline_function union_type
%type <ast> attributed_statement attributed_class_statement attributed_parameter
-%type <ast> attribute_decl attribute attributes
+%type <ast> attribute_decl attribute attributes namespace_declaration_name
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list
%type <num> returns_ref function fn is_reference is_variadic variable_modifiers
@@ -308,15 +311,29 @@ top_statement_list:
| %empty { $$ = zend_ast_create_list(0, ZEND_AST_STMT_LIST); }
;
+/* Name usable in a namespace declaration. */
+namespace_declaration_name:
+ identifier { $$ = $1; }
+ | T_NAME_QUALIFIED { $$ = $1; }
+;
+
+/* Name usable in "use" declarations (loading separator forbidden). */
namespace_name:
T_STRING { $$ = $1; }
- | namespace_name T_NS_SEPARATOR T_STRING { $$ = zend_ast_append_str($1, $3); }
+ | T_NAME_QUALIFIED { $$ = $1; }
+;
+
+/* Name usable in "use" declarations (leading separator allowed). */
+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_decl:
@@ -350,10 +367,10 @@ top_statement:
{ $$ = zend_ast_create(ZEND_AST_HALT_COMPILER,
zend_ast_create_zval_from_long(zend_get_scanned_file_offset()));
zend_stop_lexing(); }
- | T_NAMESPACE namespace_name ';'
+ | T_NAMESPACE namespace_declaration_name ';'
{ $$ = zend_ast_create(ZEND_AST_NAMESPACE, $2, NULL);
RESET_DOC_COMMENT(); }
- | T_NAMESPACE namespace_name { RESET_DOC_COMMENT(); }
+ | T_NAMESPACE namespace_declaration_name { RESET_DOC_COMMENT(); }
'{' top_statement_list '}'
{ $$ = zend_ast_create(ZEND_AST_NAMESPACE, $2, $5); }
| T_NAMESPACE { RESET_DOC_COMMENT(); }
@@ -372,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:
@@ -424,8 +437,10 @@ unprefixed_use_declaration:
;
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 T_STRING
+ { $$ = zend_ast_create(ZEND_AST_USE_ELEM, $1, $3); }
;
const_list:
diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l
index b6cd505a63..2ebe92e6bd 100644
--- a/Zend/zend_language_scanner.l
+++ b/Zend/zend_language_scanner.l
@@ -1596,10 +1596,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);
}
@@ -2288,6 +2284,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);
}
diff --git a/ext/tokenizer/tests/namespaced_names.phpt b/ext/tokenizer/tests/namespaced_names.phpt
new file mode 100644
index 0000000000..34e947b352
--- /dev/null
+++ b/ext/tokenizer/tests/namespaced_names.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Tokenization of namespaced names
+--FILE--
+<?php
+
+$code = <<<'CODE'
+<?php
+Foo
+Foo\Bar
+\Foo\Bar
+namespace\Foo
+Foo \ Bar
+CODE;
+
+foreach (PhpToken::getAll($code) as $token) {
+ echo "{$token->getTokenName()}: \"$token->text\"\n";
+}
+
+?>
+--EXPECT--
+T_OPEN_TAG: "<?php
+"
+T_STRING: "Foo"
+T_WHITESPACE: "
+"
+T_NAME_QUALIFIED: "Foo\Bar"
+T_WHITESPACE: "
+"
+T_NAME_FULLY_QUALIFIED: "\Foo\Bar"
+T_WHITESPACE: "
+"
+T_NAME_RELATIVE: "namespace\Foo"
+T_WHITESPACE: "
+"
+T_STRING: "Foo"
+T_WHITESPACE: " "
+T_NS_SEPARATOR: "\"
+T_WHITESPACE: " "
+T_STRING: "Bar"
diff --git a/ext/tokenizer/tokenizer_data.c b/ext/tokenizer/tokenizer_data.c
index 14630cdd40..9ed027920c 100644
--- a/ext/tokenizer/tokenizer_data.c
+++ b/ext/tokenizer/tokenizer_data.c
@@ -77,6 +77,9 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
REGISTER_LONG_CONSTANT("T_LNUMBER", T_LNUMBER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_DNUMBER", T_DNUMBER, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_STRING", T_STRING, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("T_NAME_FULLY_QUALIFIED", T_NAME_FULLY_QUALIFIED, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("T_NAME_RELATIVE", T_NAME_RELATIVE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("T_NAME_QUALIFIED", T_NAME_QUALIFIED, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_VARIABLE", T_VARIABLE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_INLINE_HTML", T_INLINE_HTML, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_ENCAPSED_AND_WHITESPACE", T_ENCAPSED_AND_WHITESPACE, CONST_CS | CONST_PERSISTENT);
@@ -221,6 +224,9 @@ char *get_token_type_name(int token_type)
case T_LNUMBER: return "T_LNUMBER";
case T_DNUMBER: return "T_DNUMBER";
case T_STRING: return "T_STRING";
+ case T_NAME_FULLY_QUALIFIED: return "T_NAME_FULLY_QUALIFIED";
+ case T_NAME_RELATIVE: return "T_NAME_RELATIVE";
+ case T_NAME_QUALIFIED: return "T_NAME_QUALIFIED";
case T_VARIABLE: return "T_VARIABLE";
case T_INLINE_HTML: return "T_INLINE_HTML";
case T_ENCAPSED_AND_WHITESPACE: return "T_ENCAPSED_AND_WHITESPACE";