自定义phpcs(phpcbf)空大括号去空格Sniff执行失败
解决PHPCBF空大括号修复循环报错问题
你的问题核心是Sniff在修复后触发了重复检测,导致PHPCBF进入无限循环直到达到最大次数限制。这通常是因为修复操作没有正确处理token指针位置,或者每次修复后又触发了同一规则的检测。
问题根源
当你移除{和}之间的空白时,文件的token流会发生变化,如果Sniff没有告诉PHPCBF跳过已处理的位置,下次扫描时会再次定位到修改后的大括号区域,重复执行修复操作,进而引发循环。
正确的Sniff实现方案
下面是能解决循环问题的Sniff代码,关键在于准确定位空大括号、一次性完成修复,并且处理后跳转指针避免重复检测:
use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; class EmptyBraceWhitespaceSniff implements Sniff { public function register() { return [T_OPEN_CURLY_BRACKET]; } public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $openBrace = $stackPtr; // 跳过无法匹配右大括号的情况 if (!isset($tokens[$openBrace]['bracket_closer'])) { return; } $closeBrace = $tokens[$openBrace]['bracket_closer']; $hasNonWhitespace = false; // 检查大括号中间是否只有空白字符 for ($i = $openBrace + 1; $i < $closeBrace; $i++) { if ($tokens[$i]['code'] !== T_WHITESPACE) { $hasNonWhitespace = true; break; } } if ($hasNonWhitespace) { return; } // 已经是紧凑格式,无需处理 if (($closeBrace - $openBrace) === 1) { return; } // 包裹修复操作,确保单次变更完成 $phpcsFile->fixer->beginChangeset(); // 移除所有中间的空白token for ($i = $openBrace + 1; $i < $closeBrace; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); // 跳转到右大括号的下一个token,避免重复处理当前区域 return $closeBrace + 1; } }
关键修复点
- 准确匹配成对大括号:利用
$tokens[$openBrace]['bracket_closer']获取对应的右大括号,避免定位错误。 - 排除非空白内容:确保只处理真正的空大括号(中间仅含空白),不会误改有注释或代码的大括号。
- 一次性修复:用
beginChangeset()和endChangeset()包裹修复操作,让PHPCBF将所有修改视为单次变更,减少重复扫描。 - 指针跳转:处理完成后返回
$closeBrace + 1,告诉PHPCBF从下一个token开始扫描,彻底避免重复处理当前大括号。
之前添加return $phpcsFile->numTokens没用,是因为这个操作会让PHPCBF直接跳到文件末尾,跳过后续所有内容,但如果文件中有多个需要修复的位置,第一次修复后重新扫描时还是会回到开头,再次触发当前位置的检测,导致循环。而精准跳转到下一个token才是正确的做法。
内容的提问来源于stack exchange,提问作者donatJ
相关产品推荐
相关产品推荐

