PHP Conference Japan 2024

token_get_all

(PHP 4 >= 4.2.0, PHP 5, PHP 7, PHP 8)

token_get_all將給定的原始碼分割成 PHP 詞彙符號 (Token)

說明

token_get_all(字串 $code, 整數 $flags = 0): 陣列

token_get_all() 使用 Zend 引擎的詞彙掃描器將給定的 code 字串剖析成 PHP 語言詞彙符號。

有關剖析器詞彙符號的列表,請參閱 剖析器詞彙符號列表,或使用 token_name() 將詞彙符號值轉換為其字串表示形式。

參數

code

要剖析的 PHP 原始碼。

flags

有效旗標

  • TOKEN_PARSE - 能夠辨識在特定上下文中的保留字。

回傳值

一個權杖識別碼的陣列。每個權杖識別碼可以是一個單一字元(例如:;.>! 等),或者是一個包含三個元素的陣列:元素 0 為權杖索引、元素 1 為原始權杖的字串內容、元素 2 為行號。

範例

範例 #1 token_get_all() 範例

<?php
$tokens
= token_get_all('<?php echo; ?>');

foreach (
$tokens as $token) {
if (
is_array($token)) {
echo
"第 {$token[2]} 行: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
}
}
?>

上述範例的輸出會類似以下:

Line 1: T_OPEN_TAG ('<?php ')
Line 1: T_ECHO ('echo')
Line 1: T_WHITESPACE (' ')
Line 1: T_CLOSE_TAG ('?>')

範例 #2 token_get_all() 錯誤用法範例

<?php
$tokens
= token_get_all('/* comment */');

foreach (
$tokens as $token) {
if (
is_array($token)) {
echo
"第 {$token[2]} 行: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
}
}
?>

上述範例的輸出會類似以下:

Line 1: T_INLINE_HTML ('/* comment */')
請注意,在上一個範例中,字串被解析為 T_INLINE_HTML,而不是預期的 T_COMMENT。這是因為提供的程式碼中沒有使用開始標籤。這相當於在一般檔案中將註釋放在 PHP 標籤之外。

範例 #3 使用保留字的類別之 token_get_all() 範例

<?php

$source
= <<<'code'
<?php

class A
{
const PUBLIC = 1;
}
code;

$tokens = token_get_all($source, TOKEN_PARSE);

foreach (
$tokens as $token) {
if (
is_array($token)) {
echo
token_name($token[0]) , PHP_EOL;
}
}
?>

上述範例的輸出會類似以下:

T_OPEN_TAG
T_WHITESPACE
T_CLASS
T_WHITESPACE
T_STRING
T_CONST
T_WHITESPACE
T_STRING
T_LNUMBER
如果沒有TOKEN_PARSE 旗標,倒數第二個權杖 (T_STRING) 就會是 T_PUBLIC

另請參閱

新增註解

使用者貢獻的註解 6 則註解

Dennis Robinson from basnetworks dot net
15 年前
我想要使用權杖分析器函式來計算程式碼的行數,包含計算註解。嘗試使用正規表示式來執行此操作效果不佳,因為 /* 可能出現在字串中,或其他情況。 token_get_all() 函式可以正確偵測所有註解,讓這個任務變得簡單。然而,它不會將換行字元權杖化。我編寫了以下一組函式,也將換行字元權杖化為 T_NEW_LINE。

<?php

define
('T_NEW_LINE', -1);

function
token_get_all_nl($source)
{
$new_tokens = array();

// 取得詞彙符號 (Token)
$tokens = token_get_all($source);

// 將換行符號分割成獨立的詞彙符號
foreach ($tokens as $token)
{
$token_name = is_array($token) ? $token[0] : null;
$token_data = is_array($token) ? $token[1] : $token;

// 不要分割包含在字串或多行註釋中的換行符號
if ($token_name == T_CONSTANT_ENCAPSED_STRING || substr($token_data, 0, 2) == '/*')
{
$new_tokens[] = array($token_name, $token_data);
continue;
}

// 透過換行符號分割資料
$split_data = preg_split('#(\r\n|\n)#', $token_data, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

foreach (
$split_data as $data)
{
if (
$data == "\r\n" || $data == "\n")
{
// 這是換行詞彙符號
$new_tokens[] = array(T_NEW_LINE, $data);
}
else
{
// 使用原始詞彙符號名稱新增詞彙符號
$new_tokens[] = is_array($token) ? array($token_name, $data) : $data;
}
}
}

return
$new_tokens;
}

function
token_name_nl($token)
{
if (
$token === T_NEW_LINE)
{
return
'T_NEW_LINE';
}

return
token_name($token);
}

?>

範例用法

<?php

$tokens
= token_get_all_nl(file_get_contents('somecode.php'));

foreach (
$tokens as $token)
{
if (
is_array($token))
{
echo (
token_name_nl($token[0]) . ': "' . $token[1] . '"<br />');
}
else
{
echo (
'"' . $token . '"<br />');
}
}

?>

我相信您可以利用這些函式計算程式碼行數和註釋行數。這比我之前嘗試使用正規表達式計算程式碼行數有了巨大的改進。我希望這能幫助到其他人,因為過去這個網站上許多使用者提供的範例都幫助了我。
gomodo at free dot fr
15 年前
是的,使用 get_token_all() 會有一些問題(在 WAMP 上,PHP 5.3.0 版本)

1:行號錯誤
自 PHP 5.2.2 起,token_get_all() 應該在元素 2 中返回行號。
... 但是例如(在 WAMP 上的 5.3.0),它僅在純 PHP 程式碼(不含 HTML)中才能完美運作,但如果您有一些被 token_get_all() 偵測到的 T_INLINE_HTML,有時您會發現錯誤的行號(返回下一行)... :(

2:錯誤警告訊息可能會影響迴圈
不完整的 PHP 程式碼會出現警告(例如:逐行 PHP 程式碼)
例如,如果註釋標籤未關閉,token_get_all() 會因為此警告而阻斷迴圈
警告:未結束的註釋,起始於第...行

這個問題似乎只發生在網頁模式下,而不會在 CLI 模式(PHP 命令列)中出現。

為了更高的穩定性,請僅在純 PHP 程式碼(不含 HTML)上使用 token_get_all()
首先,完整提取 PHP 程式碼(包含 PHP 開啟和關閉標籤),
其次,在純 PHP 程式碼上使用 token_get_all()。

3:為什麼沒有用於提取 PHP 程式碼的函式(我們有 Tidy 可以提取 HTML...)?

等待中,我使用了以下函式

程式碼在此文章末尾
http://www.developpez.net/forums/d786381/php/langage/
fonctions/analyser-fichier-php-token_get_all/

此函式不支援
- 舊式標記:"<? ?>" 和 "<% %>"
- heredoc 語法
- nowdoc 語法(自 PHP 5.3.0 起)
Ivan Ustanin
6 年前
注意事項:使用 TOKEN_PARSE 處理無效的 php 檔案時,可能會收到如下錯誤
解析錯誤:語法錯誤,第 15 行出現意外的 '__construct' (T_STRING),預期為 function (T_FUNCTION) 或 const (T_CONST)
請注意缺少檔名,因為此函式接受字串而非檔名,因此不知道後者。
然而,例外處理會更好。
Theriault
8 年前
T_OPEN_TAG 標記將包含第一個後續的換行符號(\r、\n 或 \r\n)、製表符號(\t)或空格。此標記之後的任何其他空格都將位於 T_WHITESPACE 標記中。

T_CLOSE_TAG 標記將包含第一個後續的換行符號(\r、\n 或 \r\n;如此處所述 https://php.dev.org.tw/manual/en/language.basic-syntax.instruction-separation.php)。此標記之後的任何其他空格都將位於 T_INLINE_HTML 標記中。
bart
7 年前
並非所有詞彙 (token) 都會以陣列形式返回。規則似乎是,如果詞彙不是變數,而是一個特定的常數字串,它就會以字串形式返回。您不會獲得行號。大括號(「{」、「}」)、小括號(「(」、「)」)、方括號(「[」、「]」)、逗號(「,」)、分號(「;」)以及許多運算子符號(「!」、「=」、「+」、「*」、「/」、「.」、「+=」...)都是這種情況。
To Top