PHP Tooling

Clean Up Redundant Code Comments with a Custom Rector Rule

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
Share on X

// Found an issue or want to contribute a tip? github.com/MrPunyapal/tips