From 5f8d648af6ef4e29a3c7f2b2029d08466c12bc6f Mon Sep 17 00:00:00 2001 From: Theodore Brown Date: Mon, 11 Aug 2025 07:18:06 -0500 Subject: [PATCH] Deprecate terminating case statements with a semicolon (#19215) Part of https://wiki.php.net/rfc/deprecations_php_8_5 Closes GH-15258 --- NEWS | 2 ++ UPGRADING | 3 +++ Zend/zend_compile.c | 5 +++++ Zend/zend_compile.h | 1 + Zend/zend_language_parser.y | 13 ++++++------- ext/opcache/tests/issue0057.phpt | 4 ++-- tests/lang/033.phpt | 3 ++- tests/lang/bug26696.phpt | 2 +- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index fa8db03972b..03711eb0a46 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ PHP NEWS been deprecated. (Girgias) . The $exclude_disabled parameter of the get_defined_functions() function has been deprecated, as it no longer has any effect since PHP 8.0. (Girgias) + . Terminating case statements with a semicolon instead of a colon has + been deprecated. (theodorejb) - DOM: . Fixed bug GH-18877 (\Dom\HTMLDocument querySelectorAll selecting only the diff --git a/UPGRADING b/UPGRADING index da3d579bb97..17b8ce21302 100644 --- a/UPGRADING +++ b/UPGRADING @@ -322,6 +322,9 @@ PHP 8.5 UPGRADE NOTES . The $exclude_disabled parameter of the get_defined_functions() function has been deprecated, as it no longer has any effect since PHP 8.0. RFC: https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_the_exclude_disabled_parameter_of_get_defined_functions + . Terminating case statements with a semicolon instead of a colon has + been deprecated. + RFC: https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_semicolon_after_case_in_switch_statement - FileInfo: . The finfo_close() function has been deprecated. diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index eb2286b9329..5527f55a25c 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6313,6 +6313,11 @@ static void zend_compile_switch(zend_ast *ast) /* {{{ */ continue; } + if (case_ast->attr == ZEND_ALT_CASE_SYNTAX) { + CG(zend_lineno) = case_ast->lineno; + zend_error(E_DEPRECATED, "Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead"); + } + zend_compile_expr(&cond_node, cond_ast); if (expr_node.op_type == IS_CONST diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a083babcd81..0decb7e848f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1127,6 +1127,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); ((ZEND_TYPE_FULL_MASK((arg_info)->type) & _ZEND_IS_TENTATIVE_BIT) != 0) #define ZEND_DIM_IS (1 << 0) /* isset fetch needed for null coalesce. Set in zend_compile.c for ZEND_AST_DIM nested within ZEND_AST_COALESCE. */ +#define ZEND_ALT_CASE_SYNTAX (1 << 1) /* deprecated switch case terminated by semicolon */ /* Attributes for ${} encaps var in strings (ZEND_AST_DIM or ZEND_AST_VAR node) */ /* ZEND_AST_VAR nodes can have any of the ZEND_ENCAPS_VAR_* flags */ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 12d93716817..3f2817b26ec 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -713,15 +713,14 @@ switch_case_list: case_list: %empty { $$ = zend_ast_create_list(0, ZEND_AST_SWITCH_LIST); } - | case_list T_CASE expr case_separator inner_statement_list + | case_list T_CASE expr ':' inner_statement_list { $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_SWITCH_CASE, $3, $5)); } - | case_list T_DEFAULT case_separator inner_statement_list + | case_list T_CASE expr ';' inner_statement_list + { $$ = zend_ast_list_add($1, zend_ast_create_ex(ZEND_AST_SWITCH_CASE, ZEND_ALT_CASE_SYNTAX, $3, $5)); } + | case_list T_DEFAULT ':' inner_statement_list { $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_SWITCH_CASE, NULL, $4)); } -; - -case_separator: - ':' - | ';' + | case_list T_DEFAULT ';' inner_statement_list + { $$ = zend_ast_list_add($1, zend_ast_create_ex(ZEND_AST_SWITCH_CASE, ZEND_ALT_CASE_SYNTAX, NULL, $4)); } ; diff --git a/ext/opcache/tests/issue0057.phpt b/ext/opcache/tests/issue0057.phpt index 20c2f2a1055..ac73859b0d3 100644 --- a/ext/opcache/tests/issue0057.phpt +++ b/ext/opcache/tests/issue0057.phpt @@ -15,9 +15,9 @@ class ZException extends Exception { function dummy($query) { try { switch ($query) { - case 1; + case 1: break; - case 2; + case 2: break; default: throw new Exception('exception'); diff --git a/tests/lang/033.phpt b/tests/lang/033.phpt index e6254d687b0..41424e40489 100644 --- a/tests/lang/033.phpt +++ b/tests/lang/033.phpt @@ -37,7 +37,8 @@ switch ($a): break; endswitch; ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Case statements followed by a semicolon (;) are deprecated, use a colon (:) instead in %s If: 11 While: 12346789 For: 0123401234 diff --git a/tests/lang/bug26696.phpt b/tests/lang/bug26696.phpt index 1d10297b12c..de0dc90ca0d 100644 --- a/tests/lang/bug26696.phpt +++ b/tests/lang/bug26696.phpt @@ -15,7 +15,7 @@ for ($i = 0; $i < $len; $i++) { $str = '*'; switch ($str[0]) { - case '*'; + case '*': echo "OK\n"; break; default: