Use a custom Rector rule to automatically strip noisy inline comments and empty docblocks across your codebase while preserving essential PHPDoc annotations.
Codebases often accumulate redundant comments over time: commented-out legacy code, obvious explanations (// set user name), or empty boilerplate docblocks generated by older IDE templates.
Manually reviewing and removing thousands of stale comments across hundreds of files is time-consuming. Using Rector, you can define an AbstractRector rule that strips non-essential comments while retaining critical PHPDoc annotations such as @param, @return, and @throws.
The Rector Implementation
namespace AppRector;
use PhpParserComment;
use PhpParserCommentDoc;
use PhpParserNode;
use RectorRectorAbstractRector;
use SymplifyRuleDocGeneratorValueObjectCodeSampleCodeSample;
use SymplifyRuleDocGeneratorValueObjectRuleDefinition;
final class RemoveUnnecessaryCommentsRector extends AbstractRector
{
// Whitelist specific comment strings or tags you want to keep
private const ALLOWED_PATTERNS = [
'@todo',
'@var',
];
public function getNodeTypes(): array
{
return [Node::class];
}
public function refactor(Node $node): ?Node
{
$comments = $node->getComments();
if ($comments === []) {
return null;
}
$filtered = [];
$changed = false;
foreach ($comments as $comment) {
if ($comment instanceof Doc) {
$cleaned = $this->cleanDocBlock($comment);
if ($cleaned !== $comment->getText()) {
if ($cleaned !== '') {
$filtered[] = new Doc($cleaned);
}
$changed = true;
} else {
$filtered[] = $comment;
}
continue;
}
// Check if regular comment contains allowed keywords
if ($this->isAllowed($comment->getText())) {
$filtered[] = $comment;
} else {
$changed = true;
}
}
if (! $changed) {
return null;
}
$node->setAttribute('comments', $filtered);
return $node;
}
private function cleanDocBlock(Doc $doc): string
{
$lines = preg_split('/\R/', $doc->getText());
$tags = [];
foreach ($lines as $line) {
$line = trim(preg_replace('/^\s*\*\s?/', '', $line));
if ($line === '') {
continue;
}
// Preserve standard PHPDoc annotations (@param, @return, @throws, etc.)
if (str_starts_with($line, '@')) {
$tags[] = $line;
}
}
if ($tags === []) {
return '';
}
return "/**\n * " . implode("\n * ", $tags) . "\n */";
}
private function isAllowed(string $text): bool
{
foreach (self::ALLOWED_PATTERNS as $allowed) {
if (str_contains($text, $allowed)) {
return true;
}
}
return false;
}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Remove redundant inline comments while retaining essential PHPDoc tags', [
new CodeSample(
<<<'CODE'
// Initialize user model
$user = new User();
CODE
,
<<<'CODE'
$user = new User();
CODE
),
]);
}
}
Registering in rector.php
Add the custom rule to your project's Rector configuration:
use AppRectorRemoveUnnecessaryCommentsRector;
use RectorConfigRectorConfig;
return RectorConfig::configure()
->withRules([
RemoveUnnecessaryCommentsRector::class,
]);
Run the refactoring dry-run to preview changes:
vendor/bin/rector process --dry-run
Summary
- Use AST-based comment manipulation in Rector to systematically clean comment noise across large codebases.
- The rule strips redundant plain comments (
// comment) while keeping meaningful docblock tags (@param,@return,@throws). - Easily extensible to whitelist specific tags or maintenance markers such as
@todo.
Tags:
PHP Rector Refactoring Clean Code Tooling