是否有 PHP linter 规则来防止明显的评论?

Are there PHP linter rules to prevent obvious comments?

我在多语言软件代码库(python、JS、java、PHP、C)上工作,我以前的同事在其中评论了所有内容。 然而,绝大多数评论是完全没有用的。 例如:

/**
 * Get warning file info
 */
function getWarningFileInfos() {
   ...
}

/**
 * Compute the speed
 */
function computeSpeed() {
    ...
}

我想设置 linter 规则以确保不会再次写入此类评论。 你知道 linters 有这样的功能,或者可以很容易地添加这个功能吗? (最好是与非英语评论兼容的 linters)

这个问题需要教会你的同事评论是为了什么以及应该写什么样的评论。

如果您只是自动屏蔽与该方法同名的评论,您最终会略有不同:

/**
 * Get warning file info
 */
function getWarningFileInfos() {
   ...
}

变为:

/**
 * Get the warning file info
 */
function getWarningFileInfos() {
   ...
}

... 并且 linter 规则将接受它。这不是一个可以通过 linting 规则解决的问题。

如果您可以要求同事提供适当的评论,请他们正确地重写评论是一个很好的练习,可以教会他们应该写什么评论。

没有 linter 可以将无用的评论转换为有用的评论。

如果你只想删除所有糟糕的评论,你可以使用正则表达式:

/\*.{1,50}\*/ 将查找所有短于 50 个字符的评论(编辑器必须支持正则表达式设置“. matches newline”)。

什么都不替换,然后手动浏览文件以检查您是否删除了任何有价值的内容。假设大多数这些愚蠢的评论都很短。 50 个字符是任意的,将其更改为最适合您的字符。

如果你真的需要它,你可以使用像这样疯狂的东西:

$c = '/**
 * Get warning file info
 */
function getWarningFileInfos() {
   ...
}

/**
 * Compute the speed
 */
function computeSpeed() {
    ...
}';

preg_match_all('~\*/[ \t]*\r?\n(?:[ \t]|\w)*function[ \t]+(\S+)[ \t]*\(~isu', $c, $matchesAll);
foreach ($matchesAll[1] as $n) {
    $words = preg_split('~(?=\p{Lu})~', $n);
    $regex = '~/\*(?:\s|\*)*' . implode('', array_map(function($w) {
        return '(?:(?:a|the)\s+)?' . preg_quote(preg_replace('~e?s$~is', '', $w), '~') . '(?:e?s)?' . '\s+';
    }, $words)) . '(?:\s|\*)*\*+/[ \t]*(?=\r?\n(?:[ \t]|\w)*function[ \t]+' . preg_quote($n, '~') . '[ \t]*\()~isu';
    var_dump($regex);
    $c = preg_replace($regex, '', $c);
}

var_dump($c);

示例输出:

string(231) "~/\*(?:\s|\*)*(?:(?:a|the)\s+)?get(?:e?s)?\s+(?:(?:a|the)\s+)?Warning(?:e?s)?\s+(?:(?:a|the)\s+)?File(?:e?s)?\s+(?:(?:a|the)\s+)?Info(?:e?s)?\s+(?:\s|\*)*\*+/[ \t]*(?=\r?\n(?:[ \t]|\w)*function[ \t]+getWarningFileInfos[ \t]*\()~isu"
string(162) "~/\*(?:\s|\*)*(?:(?:a|the)\s+)?compute(?:e?s)?\s+(?:(?:a|the)\s+)?Speed(?:e?s)?\s+(?:\s|\*)*\*+/[ \t]*(?=\r?\n(?:[ \t]|\w)*function[ \t]+computeSpeed[ \t]*\()~isu"
string(88) "
function getWarningFileInfos() {
   ...
}


function computeSpeed() {
    ...
}"

除了培训您的程序员外,可能没有其他工具,上面的代码对您有帮助吗?

GitHub上没有这样的linters,所以你得自己写一个。

PHP_CodeSniffer is best known and powerful linter in the PHP world, So here is quick and dirty implementation based on PHP_CodeSniffer 3.5.2 for your purpose, It uses similar_text函数比较函数名和注释字符串,如果百分比大于60%,则将此函数标记为错误消息"Contains unusual comment"。

文件src/Standards/Whosebug/Sniffs/Commenting/UnusualCommentSniff.php

<?php

namespace PHP_CodeSniffer\Standards\Whosebug\Sniffs\Commenting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;

class UnusualCommentSniff implements Sniff
{
    public function register()
    {
        return [T_FUNCTION];
    }

    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();
        $find   = Tokens::$methodPrefixes;
        $find[] = T_WHITESPACE;

        $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true);
        if ($tokens[$commentEnd]['code'] != T_DOC_COMMENT_CLOSE_TAG) {
            return;
        }
        $commentStart = $tokens[$commentEnd]['comment_opener'];

        $shortDesc = $this->findShortDescriptionInComment($phpcsFile, $commentStart, $commentEnd);
        $funcName = $phpcsFile->getDeclarationName($stackPtr);
        similar_text($funcName, $shortDesc, $percent);
        if ($percent > 60) {
            $error = 'Contains unusual comment';
            $fix = $phpcsFile->addFixableError($error, $stackPtr, 'code');
            if ($fix) {
                $fixer = $phpcsFile->fixer;
                for ($i = $commentStart; $i < $commentEnd + 1; $i++) {
                    $fixer->replaceToken($i, '');
                }
            }
        }
    }

    protected function findShortDescriptionInComment($phpcsFile, $commentStart, $commentEnd)
    {
        $tokens = $phpcsFile->getTokens();

        $empty = [
            T_DOC_COMMENT_WHITESPACE,
            T_DOC_COMMENT_STAR,
        ];

        $short = $phpcsFile->findNext($empty, $commentStart + 1, $commentEnd, true);
        if ($short === false) {
            return;
        }
        $shortContent = null;
        if ($tokens[$short]['code'] === T_DOC_COMMENT_STRING) {
            $shortContent = $tokens[$short]['content'];
            $shortEnd     = $short;
            for ($i = ($short + 1); $i < $commentEnd; $i++) {
                if ($tokens[$i]['code'] === T_DOC_COMMENT_STRING) {
                    if ($tokens[$i]['line'] === ($tokens[$shortEnd]['line'] + 1)) {
                        $shortContent .= $tokens[$i]['content'];
                        $shortEnd      = $i;
                    } else {
                        break;
                    }
                }
            }
        }

        return $shortContent;
    }
}

POC

像这样构建文件和目录

$ pwd
/home/gasolwu/Code/PHP_CodeSniffer/src/Standards
$ git describe
3.5.2-89-g80ebd4a1a
$ tree -C Whosebug/
Whosebug/
├── ruleset.xml
└── Sniffs
    └── Commenting
        └── UnusualCommentSniff.php

2 directories, 2 files
$ cat Whosebug/ruleset.xml
<?xml version="1.0"?>
<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Zend" xsi:noNamespaceSchemaLocation="../../../phpcs.xsd">
</ruleset>

为测试准备输入文件

$ cat input.php
<?php

class Foo
{

    /**
     * Get warning file info
     */
    private function getWarningFileInfos() {
    }

    /**
     * Compute the speed
     */
    public function computeSpeed() {
    }

    /**
     * This comment contains some useful information
     * So that should not be deleted
     */
    public function shoot() {
    }
}

运行 使用命令 phpcs

$ bin/phpcs --standard=Whosebug ./input.php

FILE: /data1/home/admin/gasolwu/Code/PHP_CodeSniffer/input.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
----------------------------------------------------------------------
  9 | ERROR | [x] Contains unusual comment
 15 | ERROR | [x] Contains unusual comment
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 44ms; Memory: 3.75MB

通过命令自动修复此类错误phpcbf

$ bin/phpcbf --standard=Whosebug ./input.php

PHPCBF RESULT SUMMARY
-----------------------------------------------------------------------------
FILE                                                         FIXED  REMAINING
-----------------------------------------------------------------------------
/data1/home/admin/gasolwu/Code/PHP_CodeSniffer/input.php     2      0
-----------------------------------------------------------------------------
A TOTAL OF 2 ERRORS WERE FIXED IN 1 FILE
-----------------------------------------------------------------------------

Time: 52ms; Memory: 3.75MB

$ cat input.php
<?php

class Foo
{


    private function getWarningFileInfos() {
    }


    public function computeSpeed() {
    }

    /**
     * This comment contains some useful information
     * So that should not be deleted
     */
    public function shoot() {
    }
}