PHP 內置 php_strip_whitespace() 僅支持文件路徑,無法直接處理字符串變量中的代碼。ThinkPHP 框架內置的 strip_whitespace() 利用 token_get_all() 詞法分析器,實現了對任意 PHP 代碼字符串的空白字符壓縮與註釋剝離。本文深度解析其核心邏輯,並提供可直接使用的增強版函數。
token_get_all($code) 將 PHP 代碼解析為「詞法單元」數組:
;、{、$)以字符串形式出現。[TOKEN_TYPE, 'token_content', line_number] 數組形式出現。遍歷單元流,根據類型決定保留、轉換或丟棄:
T_WHITESPACE)壓縮為單個空格。T_COMMENT、T_DOC_COMMENT)。T_START_HEREDOC/T_END_HEREDOC)需保持原樣。<?php
/**
* 移除 PHP 代碼字符串中的空白字符與註釋
* @param string $source PHP 代碼字符串
* @return string 處理後的代碼
*/
function strip_whitespace(string $source): string {
$tokens = token_get_all($source);
$output = '';
$lastWasWhitespace = false;
foreach ($tokens as $token) {
if (is_string($token)) {
// 單字符標記:直接輸出
$output .= $token;
$lastWasWhitespace = false;
continue;
}
[$id, $text] = $token;
match ($id) {
T_COMMENT, T_DOC_COMMENT => {
// 完全丟棄註釋
$lastWasWhitespace = false;
},
T_WHITESPACE => {
// 連續空白壓縮為單個空格
if (!$lastWasWhitespace) {
$output .= ' ';
$lastWasWhitespace = true;
}
},
T_START_HEREDOC => {
// Heredoc 開始:輸出 <<< 並進入特殊模式
$output .= '<<<';
$lastWasWhitespace = false;
},
T_END_HEREDOC => {
// Heredoc 結束:輸出結束標記,並跳過後續的分號或關閉標記
$output .= $text; // 實際為結束標識符
$lastWasWhitespace = false;
// 可選:跳過緊隨其後的分號或 ?>,避免重複輸出
},
default => {
// 其他所有 token:關鍵字、變量、字符串、數字等,原樣輸出內容
$output .= $text;
$lastWasWhitespace = false;
}
}
}
return trim($output);
}
$code = <<'PHP'
<?php
/**
* 這是文檔註釋
*/
function foo($bar) { // 行內註釋
$baz = "hello world"; /* 塊註釋 */
return $baz . '!';
}
// 末尾註釋
PHP;
echo strip_whitespace($code);
// 輸出:
//
原版中對 T_END_HEREDOC 的處理較為特殊:
case T_END_HEREDOC:
$stripStr .= "<<<\n"; // 這裡似乎有筆誤,實際應輸出結束標識符
for ($k = $i + 1; $k < $j; $k++) {
if (is_string($tokens[$k]) && $tokens[$k] === ';') {
$i = $k; // 跳過分號
break;
} elseif ($tokens[$k][0] === T_CLOSE_TAG) {
break;
}
}
break;
建議使用上述 match 表達式版本,邏輯更清晰、兼容 PHP 8.0+,並正確處理 Heredoc/Nowdoc 內部不應被壓縮的空白。
| 場景 | 適用性 | 說明 |
|---|---|---|
| 代碼壓縮/混淆預處理 | ✅ 高 | 減小體積,配合變量重命名等進一步混淆 |
| 模板引擎編譯輸出優化 | ✅ 高 | 編譯後的 PHP 模板去除註釋空白,提升執行速度 |
| 代碼審計/靜態分析預處理 | ✅ 中 | 統一代碼風格,便於後續 AST 分析 |
| 保留語義的代碼格式化 | ❌ 否 | 本函數會破壞縮進、換行,不可用於美化代碼 |
| 處理非 PHP 代碼(JS/CSS/HTML) | ❌ 否 | token_get_all 僅識別 PHP 語法 |
基於 token_get_all() 的詞法分析是 PHP 元編程的基石。通過精確識別 T_WHITESPACE、T_COMMENT 等單元類型,我們能在不破壞代碼語義的前提下實現「去註釋、壓縮空白」。掌握此技術,可構建代碼壓縮器、模板編譯優化器、靜態分析預處理器等進階工具。