Skip to content

Commit 8ebb223

Browse files
committed
feat: add sniff to enforce short echo tag on single-line echoing
1 parent dacb6d6 commit 8ebb223

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace InpsydeTemplates\Sniffs\Formatting;
6+
7+
use PHP_CodeSniffer\Files\File;
8+
use PHP_CodeSniffer\Sniffs\Sniff;
9+
use PHP_CodeSniffer\Util\Tokens;
10+
11+
/**
12+
* @psalm-type Token = array{
13+
* type: string,
14+
* code: string|int,
15+
* line: int
16+
* }
17+
*/
18+
final class ShortEchoTagSniff implements Sniff
19+
{
20+
/**
21+
* @return list<int|string>
22+
*/
23+
public function register(): array
24+
{
25+
return [
26+
T_ECHO,
27+
];
28+
}
29+
30+
/**
31+
* @param File $phpcsFile
32+
* @param int $stackPtr
33+
*
34+
* phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration
35+
*/
36+
public function process(File $phpcsFile, $stackPtr): void
37+
{
38+
// phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration
39+
40+
/** @var array<int, Token> $tokens */
41+
$tokens = $phpcsFile->getTokens();
42+
$currentLine = $tokens[$stackPtr]['line'];
43+
44+
$prevPtr = $phpcsFile->findPrevious(
45+
Tokens::$emptyTokens,
46+
($stackPtr - 1),
47+
null,
48+
true
49+
);
50+
51+
if (!is_int($prevPtr) || !isset($tokens[$prevPtr])) {
52+
return;
53+
}
54+
55+
$prevToken = $tokens[$prevPtr];
56+
57+
if ($prevToken['line'] !== $currentLine) {
58+
return;
59+
}
60+
61+
if ($prevToken['code'] !== T_OPEN_TAG) {
62+
return;
63+
}
64+
65+
$closeTagPtr = $phpcsFile->findNext(
66+
T_CLOSE_TAG,
67+
($stackPtr + 1),
68+
);
69+
70+
if (
71+
!is_int($closeTagPtr)
72+
|| !isset($tokens[$closeTagPtr])
73+
|| $tokens[$closeTagPtr]['line'] !== $currentLine
74+
) {
75+
return;
76+
}
77+
78+
$message = sprintf(
79+
'Single line output on line %d'
80+
. ' should use short echo tag `<?= ` instead of `<?php echo`.',
81+
$currentLine
82+
);
83+
84+
if ($phpcsFile->addFixableWarning($message, $stackPtr, 'Encouraged')) {
85+
$this->fix($prevPtr, $stackPtr, $phpcsFile);
86+
}
87+
}
88+
89+
private function fix(int $openTagPtr, int $echoPtr, File $file): void
90+
{
91+
$fixer = $file->fixer;
92+
$fixer->beginChangeset();
93+
94+
$fixer->replaceToken($echoPtr, '');
95+
$fixer->replaceToken($openTagPtr, '<?=');
96+
97+
$fixer->endChangeset();
98+
}
99+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
// @phpcsSniff InpsydeTemplates.Formatting.ShortEchoTag
6+
7+
echo 'content';
8+
9+
echo 'content', 'yet another';
10+
11+
echo ('content'), 'yet';
12+
13+
echo htmlentities('content');
14+
15+
echo $GLOBALS['flag'] ? 'yes' : 'no'; echo 'maybe', 'no'; ?>
16+
17+
<?php echo 'content';
18+
echo 'no' ?>
19+
20+
<?php echo 'content' // @phpcsWarningOnThisLine ?>
21+
22+
<?php echo 'content', 'yet another'; // @phpcsWarningOnThisLine ?>
23+
24+
<?php echo ('content'), 'yet'; // @phpcsWarningOnThisLine ?>
25+
26+
<?php echo htmlentities('content') // @phpcsWarningOnThisLine ?>
27+
28+
<?php echo $GLOBALS['flag'] ? 'yes' : 'no'; echo 'maybe', 'no'; // @phpcsWarningOnThisLine ?>

0 commit comments

Comments
 (0)