diff --git a/Zend/tests/gh9500.phpt b/Zend/tests/gh9500.phpt new file mode 100644 index 0000000000000..4afc8c579677f --- /dev/null +++ b/Zend/tests/gh9500.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug GH-9500: Disjunctive Normal Form Types - readonly property followed by ( +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/readonly_function.phpt b/Zend/tests/readonly_function.phpt index 0262b3b7348ce..35102d36b9dcd 100644 --- a/Zend/tests/readonly_function.phpt +++ b/Zend/tests/readonly_function.phpt @@ -7,10 +7,34 @@ function readonly() { echo "Hi!\n"; } +class A { + const readonly = 'Const hi!'; + + static function readonly() { + echo "Static hi!\n"; + } +} + +class B { + public $readonly = 'Prop hi!'; + + function readonly() { + echo "Instance hi!\n"; + } +} + +$b = new B(); + readonly(); -readonly (); +echo A::readonly, "\n"; +A::readonly(); +$b->readonly(); +echo $b->readonly, "\n"; ?> --EXPECT-- Hi! -Hi! +Const hi! +Static hi! +Instance hi! +Prop hi! diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 7194f70b9d471..f0c6622171ae0 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -278,6 +278,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type attribute_decl attribute attributes attribute_group namespace_declaration_name %type match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list %type enum_declaration_statement enum_backing_type enum_case enum_case_expr +%type function_name %type returns_ref function fn is_reference is_variadic variable_modifiers %type method_modifiers non_empty_member_modifiers member_modifier @@ -560,8 +561,17 @@ unset_variable: variable { $$ = zend_ast_create(ZEND_AST_UNSET, $1); } ; +function_name: + T_STRING { $$ = $1; } + | T_READONLY { + zval zv; + if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } + $$ = zend_ast_create_zval(&zv); + } +; + function_declaration_statement: - function returns_ref T_STRING backup_doc_comment '(' parameter_list ')' return_type + function returns_ref function_name 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; } @@ -1270,6 +1280,11 @@ lexical_var: function_call: name argument_list { $$ = zend_ast_create(ZEND_AST_CALL, $1, $2); } + | T_READONLY argument_list { + zval zv; + if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } + $$ = zend_ast_create(ZEND_AST_CALL, zend_ast_create_zval(&zv), $2); + } | class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list { $$ = zend_ast_create(ZEND_AST_STATIC_CALL, $1, $3, $4); } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index a367c2acb82da..c73a50948d6bc 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1729,12 +1729,6 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN_WITH_IDENT(T_READONLY); } -/* Don't treat "readonly(" as a keyword, to allow using it as a function name. */ -"readonly"[ \n\r\t]*"(" { - yyless(strlen("readonly")); - RETURN_TOKEN_WITH_STR(T_STRING, 0); -} - "unset" { RETURN_TOKEN_WITH_IDENT(T_UNSET); }