Skip to content

Commit 394e914

Browse files
committed
Added PhpCsFixer rule for variable names using camelCase.
1 parent 16f2622 commit 394e914

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor/
2+
composer.lock

composer.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "dragonwize/php-code-quality",
3+
"description": "Opinionated PHP code quality config.",
4+
"type": "library",
5+
"require": {
6+
"php": ">=8.5"
7+
},
8+
"require-dev": {
9+
"friendsofphp/php-cs-fixer": "^3.94",
10+
"phpstan/phpstan": "^2.1",
11+
"phpstan/extension-installer": "^1.4",
12+
"phpunit/phpunit": "^13.0"
13+
},
14+
"license": "MIT",
15+
"autoload": {
16+
"psr-4": {
17+
"Dragonwize\\PhpCodeQuality\\": "src/"
18+
}
19+
},
20+
"authors": [
21+
{
22+
"name": "dragonwize",
23+
"email": "dragonwize@gmail.com"
24+
}
25+
],
26+
"minimum-stability": "stable",
27+
"config": {
28+
"allow-plugins": {
29+
"phpstan/extension-installer": true
30+
}
31+
}
32+
}
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 Dragonwize\PhpCodeQuality\PhpCsFixer\Rule;
6+
7+
use PhpCsFixer\Fixer\FixerInterface;
8+
use PhpCsFixer\FixerDefinition\CodeSample;
9+
use PhpCsFixer\FixerDefinition\FixerDefinition;
10+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
11+
use PhpCsFixer\Tokenizer\Token;
12+
use PhpCsFixer\Tokenizer\Tokens;
13+
14+
final class VariableNameCaseFixer implements FixerInterface
15+
{
16+
public function getName(): string
17+
{
18+
return 'Dragonwize/variable_name_case';
19+
}
20+
21+
public function getDefinition(): FixerDefinitionInterface
22+
{
23+
return new FixerDefinition(
24+
'Enforce camelCase for variable names.',
25+
[
26+
new CodeSample("<?php \$my_variable = 2;\n"),
27+
],
28+
'Make sure to run a static analyzer after changes.',
29+
);
30+
}
31+
32+
public function isCandidate(Tokens $tokens): bool
33+
{
34+
return $tokens->isAnyTokenKindsFound([\T_VARIABLE, \T_STRING_VARNAME]);
35+
}
36+
37+
public function isRisky(): bool
38+
{
39+
return true;
40+
}
41+
42+
public function fix(\SplFileInfo $file, Tokens $tokens): void
43+
{
44+
if ($tokens->count() > 0 && $this->isCandidate($tokens) && $this->supports($file)) {
45+
$this->applyFix($file, $tokens);
46+
}
47+
}
48+
49+
public function getPriority(): int
50+
{
51+
return 0;
52+
}
53+
54+
public function supports(\SplFileInfo $file): bool
55+
{
56+
return true;
57+
}
58+
59+
private function applyFix(\SplFileInfo $file, Tokens $tokens): void
60+
{
61+
foreach ($tokens as $index => $token) {
62+
if (!$token->isGivenKind([\T_VARIABLE, \T_STRING_VARNAME, \T_PROPERTY_C])) {
63+
continue;
64+
}
65+
66+
$content = $token->getContent();
67+
68+
// Skip $this and superglobals
69+
if ($this->shouldSkip($content)) {
70+
continue;
71+
}
72+
73+
$newName = $this->toCamelCase($content);
74+
75+
if ($content !== $newName) {
76+
$tokens[$index] = new Token([$token->getId(), $newName]);
77+
}
78+
}
79+
}
80+
81+
private function shouldSkip(string $name): bool
82+
{
83+
// Skip specific variable names.
84+
if ($name === '$this') {
85+
return true;
86+
}
87+
88+
if (\array_key_exists(ltrim($name, '$'), $GLOBALS)) {
89+
return true;
90+
}
91+
92+
return false;
93+
}
94+
95+
private function toCamelCase(string $variableName): string
96+
{
97+
return str_replace('_', '', ucwords(trim($variableName), '_ '));
98+
}
99+
}

0 commit comments

Comments
 (0)