• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPCompatibility / PHPCompatibility / 19804455605

30 Nov 2025 08:31PM UTC coverage: 98.306% (-0.04%) from 98.346%
19804455605

push

github

web-flow
Merge pull request #2014 from PHPCompatibility/php-8.5/new-removedterminatingcasewithsemicolon-sniff

PHP 8.5 | ✨ New `PHPCompatibility.ControlStructures.RemovedTerminatingCaseWithSemicolon` sniff (RFC)

30 of 34 new or added lines in 1 file covered. (88.24%)

21 existing lines in 15 files now uncovered.

8355 of 8499 relevant lines covered (98.31%)

20.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.24
/PHPCompatibility/Sniffs/ControlStructures/RemovedTerminatingCaseWithSemicolonSniff.php
1
<?php
2
/**
3
 * PHPCompatibility, an external standard for PHP_CodeSniffer.
4
 *
5
 * @package   PHPCompatibility
6
 * @copyright 2012-2020 PHPCompatibility Contributors
7
 * @license   https://opensource.org/licenses/LGPL-3.0 LGPL3
8
 * @link      https://github.com/PHPCompatibility/PHPCompatibility
9
 */
10

11
namespace PHPCompatibility\Sniffs\ControlStructures;
12

13
use PHPCompatibility\Helpers\ScannedCode;
14
use PHPCompatibility\Sniff;
15
use PHP_CodeSniffer\Files\File;
16
use PHP_CodeSniffer\Util\Tokens;
17

18
/**
19
 * Detect use of a semicolon to terminate a switch case/default statement.
20
 *
21
 * This has been deprecated in PHP 8.5.
22
 *
23
 * PHP version 8.5
24
 *
25
 * @link https://wiki.php.net/rfc/deprecations_php_8_5#deprecate_semicolon_after_case_in_switch_statement
26
 * @link https://www.php.net/manual/en/control-structures.switch.php
27
 *
28
 * @since 10.0.0
29
 */
30
final class RemovedTerminatingCaseWithSemicolonSniff extends Sniff
31
{
32

33
    /**
34
     * Returns an array of tokens this test wants to listen for.
35
     *
36
     * @since 10.0.0
37
     *
38
     * @return array<int|string>
39
     */
40
    public function register()
8✔
41
    {
42
        return [
4✔
43
            \T_CASE,
8✔
44
            \T_DEFAULT,
4✔
45
        ];
4✔
46
    }
47

48
    /**
49
     * Processes this test, when one of its tokens is encountered.
50
     *
51
     * @since 10.0.0
52
     *
53
     * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
54
     * @param int                         $stackPtr  The position of the current token in the
55
     *                                               stack passed in $tokens.
56
     *
57
     * @return void
58
     */
59
    public function process(File $phpcsFile, $stackPtr)
16✔
60
    {
61
        if (ScannedCode::shouldRunOnOrAbove('8.5') === false) {
16✔
62
            return;
8✔
63
        }
64

65
        $tokens = $phpcsFile->getTokens();
8✔
66

67
        if (isset($tokens[$stackPtr]['scope_opener']) === false) {
8✔
68
            return;
4✔
69
        }
70

71
        $scopeOpener = $tokens[$stackPtr]['scope_opener'];
4✔
72
        if ($tokens[$scopeOpener]['code'] === \T_COLON) {
4✔
73
            // All good, nothing to do.
74
            return;
4✔
75
        }
76

77
        /*
78
         * If a case body is wrapped within curly braces, PHPCS sets the open brace as the scope opener,
79
         * so we need to walk back to check for the _real_ opener.
80
         */
81
        if ($tokens[$scopeOpener]['code'] === \T_OPEN_CURLY_BRACKET) {
4✔
82
            $prevNonEmpty = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($scopeOpener - 1), null, true);
4✔
83
            if ($tokens[$prevNonEmpty]['code'] === \T_COLON) {
4✔
84
                // All good, nothing to do.
85
                return;
4✔
86
            }
87

88
            // Override what we regard as the scope opener.
89
            $scopeOpener = $prevNonEmpty;
4✔
90
        }
91

92
        /*
93
         * The scope opener can now only be one of two tokens: either the semicolon or a PHP close tag with an implied semicolon.
94
         * In both cases, this is deprecated.
95
         */
96
        $terminator = 'a semicolon';
4✔
97
        if ($tokens[$scopeOpener]['code'] === \T_CLOSE_TAG) {
4✔
98
            $terminator = 'an implied semicolon';
4✔
99
        }
100

101
        $fix = $phpcsFile->addFixableWarning(
4✔
102
            'Terminating a switch case statement with %s is deprecated since PHP 8.5.',
4✔
103
            $scopeOpener,
4✔
104
            'Deprecated',
4✔
105
            [$terminator]
4✔
106
        );
2✔
107

108
        if ($fix === true) {
4✔
NEW
109
            if ($tokens[$scopeOpener]['code'] === \T_SEMICOLON) {
×
NEW
110
                $phpcsFile->fixer->replaceToken($scopeOpener, ':');
×
111
            } else {
112
                // This is a PHP close tag. Figure out where to place the colon.
NEW
113
                $prevNonEmpty = $phpcsFile->findPrevious(Tokens::EMPTY_TOKENS, ($scopeOpener - 1), null, true);
×
NEW
114
                $phpcsFile->fixer->addContent($prevNonEmpty, ':');
×
115
            }
116
        }
117
    }
2✔
118
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc