54

从 PHP 文件中删除注释的最佳方法是什么?

我想做一些类似于 strip-whitespace() 的事情——但它也不应该删除换行符。

例如,

我要这个:

<?PHP
// something
if ($whatsit) {
    do_something(); # we do something here
    echo '<html>Some embedded HTML</html>';
}
/* another long
comment
*/
some_more_code();
?>

成为:

<?PHP
if ($whatsit) {
    do_something();
    echo '<html>Some embedded HTML</html>';
}
some_more_code();
?>

(尽管如果空行仍然保留在删除注释的位置,那就不行了。)

这可能是不可能的,因为需要保留嵌入的 HTML——这就是在谷歌上出现的问题。

4

14 回答 14

64

我会使用标记器。这是我的解决方案。它应该适用于 PHP 4 和 5:

$fileStr = file_get_contents('path/to/file');
$newStr  = '';

$commentTokens = array(T_COMMENT);
    
if (defined('T_DOC_COMMENT')) {
    $commentTokens[] = T_DOC_COMMENT; // PHP 5
}

if (defined('T_ML_COMMENT')) {
    $commentTokens[] = T_ML_COMMENT;  // PHP 4
}

$tokens = token_get_all($fileStr);

foreach ($tokens as $token) {    
    if (is_array($token)) {
        if (in_array($token[0], $commentTokens)) {
            continue;
        }
        
        $token = $token[1];
    }

    $newStr .= $token;
}

echo $newStr;
于 2009-02-02T16:53:54.293 回答
45

用于php -w <sourcefile>生成去除注释和空格的文件,然后使用PHP_Beautifier 之类的美化器重新格式化以提高可读性。

于 2009-02-02T17:02:22.247 回答
9
$fileStr = file_get_contents('file.php');
foreach (token_get_all($fileStr) as $token ) {
    if ($token[0] != T_COMMENT) {
        continue;
    }
    $fileStr = str_replace($token[1], '', $fileStr);
}

echo $fileStr;
于 2009-02-02T17:06:17.467 回答
9

这是上面发布的函数,修改为递归地从目录及其所有子目录中的所有 PHP 文件中删除所有注释:

function rmcomments($id) {
    if (file_exists($id)) {
        if (is_dir($id)) {
            $handle = opendir($id);
            while($file = readdir($handle)) {
                if (($file != ".") && ($file != "..")) {
                    rmcomments($id . "/" . $file); }}
            closedir($handle); }
        else if ((is_file($id)) && (end(explode('.', $id)) == "php")) {
            if (!is_writable($id)) { chmod($id, 0777); }
            if (is_writable($id)) {
                $fileStr = file_get_contents($id);
                $newStr  = '';
                $commentTokens = array(T_COMMENT);
                if (defined('T_DOC_COMMENT')) { $commentTokens[] = T_DOC_COMMENT; }
                if (defined('T_ML_COMMENT')) { $commentTokens[] = T_ML_COMMENT; }
                $tokens = token_get_all($fileStr);
                foreach ($tokens as $token) {
                    if (is_array($token)) {
                        if (in_array($token[0], $commentTokens)) { continue; }
                        $token = $token[1]; }
                    $newStr .= $token; }
                if (!file_put_contents($id, $newStr)) {
                    $open = fopen($id, "w");
                    fwrite($open, $newStr);
                    fclose($open);
                }
            }
        }
    }
}

rmcomments("path/to/directory");
于 2011-11-15T10:49:31.503 回答
4

更强大的版本:删除文件夹中的所有评论

<?php
    $di = new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS);
    $it = new RecursiveIteratorIterator($di);
    $fileArr = [];
    foreach($it as $file) {
        if(pathinfo($file, PATHINFO_EXTENSION) == "php") {
            ob_start();
            echo $file;
            $file = ob_get_clean();
            $fileArr[] = $file;
        }
    }
    $arr = [T_COMMENT, T_DOC_COMMENT];
    $count = count($fileArr);
    for($i=1; $i < $count; $i++) {
        $fileStr = file_get_contents($fileArr[$i]);
        foreach(token_get_all($fileStr) as $token) {
            if(in_array($token[0], $arr)) {
                $fileStr = str_replace($token[1], '', $fileStr);
            }
        }
        file_put_contents($fileArr[$i], $fileStr);
    }
于 2016-01-03T14:47:15.073 回答
2

如果您已经使用UltraEdit之类的编辑器,您可以打开一个或多个 PHP 文件,然后使用简单的 Find&Replace ( Ctrl+ R)和以下Perl 正则表达式

(?s)/\*.*\*/

请注意,上面的正则表达式也会删除字符串中的注释,即,echo "hello/*babe*/";/*babe*/将被删除。因此,如果您要从中删除评论的文件很少,这可能是一个解决方案。为了绝对确保它不会错误地替换不是注释的内容,您必须运行Find&Replace命令并在每次替换时批准。

于 2014-02-25T13:08:41.957 回答
2

Bash 解决方案:如果要从当前目录开始的所有 PHP 文件中递归删除注释,可以在终端中编写此单行代码。(它使用temp1文件来存储 PHP 内容以供处理。)

请注意,这将删除所有带有注释的空格。

 find . -type f -name '*.php' | while read VAR; do php -wq $VAR > temp1  ;  cat temp1 > $VAR; done

然后你应该删除temp1文件之后。

如果安装了PHP_BEAUTIFER ,那么您可以获得格式良好的代码,无需注释

 find . -type f -name '*.php' | while read VAR; do php -wq $VAR > temp1; php_beautifier temp1 > temp2;  cat temp2 > $VAR; done;

然后删除两个文件(temp1temp2)。

于 2016-08-13T03:53:48.073 回答
1
/*
* T_ML_COMMENT does not exist in PHP 5.
* The following three lines define it in order to
* preserve backwards compatibility.
*
* The next two lines define the PHP 5 only T_DOC_COMMENT,
* which we will mask as T_ML_COMMENT for PHP 4.
*/

if (! defined('T_ML_COMMENT')) {
    define('T_ML_COMMENT', T_COMMENT);
} else {
    define('T_DOC_COMMENT', T_ML_COMMENT);
}

/*
 * Remove all comment in $file
 */

function remove_comment($file) {
    $comment_token = array(T_COMMENT, T_ML_COMMENT, T_DOC_COMMENT);

    $input = file_get_contents($file);
    $tokens = token_get_all($input);
    $output = '';

    foreach ($tokens as $token) {
        if (is_string($token)) {
            $output .= $token;
        } else {
            list($id, $text) = $token;

            if (in_array($id, $comment_token)) {
                $output .= $text;
            }
        }
    }

    file_put_contents($file, $output);
}

/*
 * Glob recursive
 * @return ['dir/filename', ...]
 */

function glob_recursive($pattern, $flags = 0) {
    $file_list = glob($pattern, $flags);

    $sub_dir = glob(dirname($pattern) . '/*', GLOB_ONLYDIR);
    // If sub directory exist
    if (count($sub_dir) > 0) {
        $file_list = array_merge(
            glob_recursive(dirname($pattern) . '/*/' . basename($pattern), $flags),
            $file_list
        );
    }

    return $file_list;
}

// Remove all comment of '*.php', include sub directory
foreach (glob_recursive('*.php') as $file) {
    remove_comment($file);
}
于 2013-04-08T14:39:20.933 回答
1

对于 Ajax 和 JSON 响应,我使用以下 PHP 代码从 HTML/JavaScript 代码中删除注释,因此它会更小(我的代码增加了大约 15%)。

// Replace doubled spaces with single ones (ignored in HTML any way)
$html = preg_replace('@(\s){2,}@', '\1', $html);
// Remove single and multiline comments, tabs and newline chars
$html = preg_replace(
    '@(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|((?<!:)//.*)|[\t\r\n]@i',
    '',
    $html
);

它简短而有效,但如果您的代码语法错误,它可能会产生意想不到的结果。

于 2013-06-18T17:39:02.813 回答
1

在命令提示符下运行命令php --strip file.php(例如cmd.exe),然后浏览到WriteCodeOnline

在这里,file.php是您自己的文件。

1

于 2017-01-18T19:11:04.680 回答
1

在 2019 年,它可以像这样工作:

<?php
/*   hi there !!!
here are the comments */
//another try

echo removecomments('index.php');

/*   hi there !!!
here are the comments */
//another try
function removecomments($f){
    $w=Array(';','{','}');
    $ts = token_get_all(php_strip_whitespace($f));
    $s='';
    foreach($ts as $t){
        if(is_array($t)){
            $s .=$t[1];
        }else{
            $s .=$t;
            if( in_array($t,$w) ) $s.=chr(13).chr(10);
        }
    }

    return $s;
}

?>

如果你想查看结果,让我们先在XAMPP中运行它,然后你会得到一个空白页面,但是如果你右键单击并单击查看源代码,你会得到你的 PHP 脚本......它正在加载自己并删除所有评论和标签。

我也更喜欢这个解决方案,因为我用它来加速我的框架一个文件引擎“m.php”,在php_strip_whitespace之后,我观察到的所有没有这个脚本的源代码都是最慢的:我做了 10 个基准测试,然后我计算了数学平均值(我认为 PHP 7 在解析时正在恢复丢失的 cr_lf,或者在这些丢失时需要一段时间)。

于 2019-05-20T10:52:45.537 回答
1

在接受答案之后,我也需要保留文件的行号,所以这里是接受答案的变体:

    /**
     * Removes the php comments from the given valid php string, and returns the result.
     *
     * Note: a valid php string must start with <?php.
     *
     * If the preserveWhiteSpace option is true, it will replace the comments with some whitespaces, so that
     * the line numbers are preserved.
     *
     *
     * @param string $str
     * @param bool $preserveWhiteSpace
     * @return string
     */
    function removePhpComments(string $str, bool $preserveWhiteSpace = true): string
    {
        $commentTokens = [
            \T_COMMENT,
            \T_DOC_COMMENT,
        ];
        $tokens = token_get_all($str);


        if (true === $preserveWhiteSpace) {
            $lines = explode(PHP_EOL, $str);
        }


        $s = '';
        foreach ($tokens as $token) {
            if (is_array($token)) {
                if (in_array($token[0], $commentTokens)) {
                    if (true === $preserveWhiteSpace) {
                        $comment = $token[1];
                        $lineNb = $token[2];
                        $firstLine = $lines[$lineNb - 1];
                        $p = explode(PHP_EOL, $comment);
                        $nbLineComments = count($p);
                        if ($nbLineComments < 1) {
                            $nbLineComments = 1;
                        }
                        $firstCommentLine = array_shift($p);

                        $isStandAlone = (trim($firstLine) === trim($firstCommentLine));

                        if (false === $isStandAlone) {
                            if (2 === $nbLineComments) {
                                $s .= PHP_EOL;
                            }

                            continue; // Just remove inline comments
                        }

                        // Stand-alone case
                        $s .= str_repeat(PHP_EOL, $nbLineComments - 1);
                    }
                    continue;
                }
                $token = $token[1];
            }

            $s .= $token;
        }
        return $s;
    }

注意:这是针对 PHP 7+ 的(我不关心与旧 PHP 版本的向后兼容性)。

于 2020-07-23T09:54:47.320 回答
0

问题是,一个不太健壮的匹配算法(例如简单的正则表达式)会在它明显不应该的时候开始剥离:

if (preg_match('#^/*' . $this->index . '#', $this->permalink_structure)) {  

它可能不会影响您的代码,但最终有人会被您的脚本所吸引。因此,您将不得不使用一个比您预期的更了解该语言的实用程序。

于 2009-02-02T16:51:14.563 回答
0

php -w或者php_strip_whitespace($filename);

文件

于 2019-07-11T10:33:57.533 回答