使用解析器标记在PHP中删除允许的空格

时间:2011-02-05 18:04:56

标签: php whitespace minify token

我正在尝试创建一个简单的脚本,从PHP文件/字符串中删除所有不必要的空格。

我已成功使用标记解析字符串,但没有看到删除“额外”空格的好方法。

例如,

function test() { return TRUE; }

应该是

function test(){return TRUE;}

而不是

functiontest(){returnTRUE;}

如果只删除T_WHITESPACE标记,则最终会得到最后一个版本。

我是否缺少删除空格的内容,但在“函数”和“返回”之类的内容后保留空格。谢谢!

3 个答案:

答案 0 :(得分:3)

$newSource = '';
foreach (token_get_all($source) as $i => $token) {
    if (!is_array($token)) {
        $newSource .= $token;
    }

    if ($token[0] == T_WHITESPACE) {
        if (   isset($tokens[$i - 1])      && isset($tokens[$i + 1])
            && is_array($tokens[$i - 1])   && is_array($tokens[$i + 1])
            && isLabel($tokens[$i - 1][1]) && isLabel($tokens[$i + 1][1])
        ) {
            $newSource .= ' ';
        }
    } else {
        $newSource .= $token[1];
    }
}

function isLabel($str) {
    return preg_match('~^[a-zA-Z0-9_\x7f-\xff]+$~', $str);
}

除了在其两侧都有LABEL的情况之外,总是允许删除空格。我检查一下,并且不添加任何内容或单个空格字符。

我知道另一个特殊情况,空白很重要:T_END_HEREDOC必须跟;\n。不允许在这里压缩或剥离空间。所以,如果这对你很重要,你可以简单地添加;)

答案 1 :(得分:1)

好吧,T_WHITESPACE可以是空格或换行符等等。因此,一个简单的方法是自动将所有T_WHITESPACE个实例替换为一个只包含一个空格的新实例。

但是对于一个更聪明的方法,只需浏览list of parser tokens,然后找出哪些应该有一个空格,哪些不应该(像这样):

foreach ($tokens as $k => $val) {
    if (is_array($val) && $val[0] == T_WHITESPACE) {
        if (!is_array($tokens[$k - 1])) {
            //remove this space
        } else {
            switch ($tokens[$k - 1][0]) {
                case T_ABSTRACT:
                case T_FUNCTION:
                //.. other keeps here:
                   continue;
                   break;
                default:
                    //remove the space
             }
         }
    }
}

还有一点需要注意,不要为了表现而这样做。如果您使用的是OPCODE缓存(例如APC),那么您将看到很多工作没有任何好处。如果你没有使用它,为什么不是你?

答案 2 :(得分:1)

你的努力是徒劳的。

php -w

允许已经从脚本中删除空格。它使用更复杂的逻辑来从令牌流中删除空格 以下是zend_strip()中的zend_highlight.c函数:

while ((token_type=lex_scan(&token TSRMLS_CC))) {
    switch (token_type) {
        case T_WHITESPACE:
            if (!prev_space) {
                zend_write(" ", sizeof(" ") - 1);
                prev_space = 1;
            }
                    /* lack of break; is intentional */
        case T_COMMENT:
        case T_DOC_COMMENT:
            token.type = 0;
            continue;

        case T_END_HEREDOC:
            zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            efree(token.value.str.val);
            /* read the following character, either newline or ; */
            if (lex_scan(&token TSRMLS_CC) != T_WHITESPACE) {
                zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            }
            zend_write("\n", sizeof("\n") - 1);
            prev_space = 1;
            token.type = 0;
            continue;

        default:
            zend_write(LANG_SCNG(yy_text), LANG_SCNG(yy_leng));
            break;
    }

    if (token.type == IS_STRING) {
        switch (token_type) {
            case T_OPEN_TAG:
            case T_OPEN_TAG_WITH_ECHO:
            case T_CLOSE_TAG:
            case T_WHITESPACE:
            case T_COMMENT:
            case T_DOC_COMMENT:
                break;

            default:
                efree(token.value.str.val);
                break;
        }
    }
    prev_space = token.type = 0;
}