token_get_all

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

token_get_all将给定源代码拆分为 PHP 标记

说明

token_get_all(string $code, int $flags = 0): array

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
"Line {$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
"Line {$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

参见

添加注释

用户贡献注释 8 则注释

来自 basnetworks dot net 的 Dennis Robinson
15 年前
我想要使用标记器函数来计算源代码行数,包括计算注释。尝试使用正则表达式来完成此任务效果不佳,因为在字符串中出现 /* 或其他情况。token_get_all() 函数通过正确检测所有注释使此任务变得容易。但是,它不会标记换行符。我编写了以下一组函数来将换行符也标记为 T_NEW_LINE。

<?php

define
('T_NEW_LINE', -1);

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

// 获取令牌
$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 年前
是的,在 WAMP 上,PHP 5.3.0 上存在一些问题 (使用 get_token_all() )

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 命令行)中,但只会出现在 web 模式中。

等待更多稳定性,只对 PHP 代码(而不是 HTML 混合代码)使用 token_get_all()
首先完全提取 PHP 代码(带开闭 PHP 标签),
其次对纯 PHP 代码使用 token_get_all()。

3: 为什么没有提取 PHP 代码的函数(为了提取 HTML,我们有 Tidy..)?

等待,我用了一个函数

帖子结尾处的代码
http://www.developpez.net/forums/d786381/php/langage/
fonctions/analyser-fichier-php-token_get_all/

此函数不支持
- 旧语法:"<? ?>" 和 "<% %>"
- heredoc 语法
- nowdoc 语法(从 PHP 5.3.0 开始)
Ivan Ustanin
5 年前
提醒:当使用 TOKEN_PARSE 处理无效的 php 文件时,可能会出现类似的错误
解析错误:语法错误,意外的 '__construct' (T_STRING),预期 function (T_FUNCTION) 或 const (T_CONST) 在第 15 行
注意缺少文件名,因为此函数接受字符串,而不是文件名,因此不知道后者。
但是,更希望出现异常。
Theriault
8 年前
T_OPEN_TAG 令牌将包含第一个尾随换行符(\r、\n 或 \r\n)、制表符(\t)或空格。此令牌后的任何额外空格将位于 T_WHITESPACE 令牌中。

T_CLOSE_TAG 令牌将包含第一个尾随换行符(\r、\n 或 \r\n;如这里所述 https://php.net/manual/en/language.basic-syntax.instruction-separation.php)。此令牌后的任何额外空格将位于 T_INLINE_HTML 令牌中。
bart
7 年前
并非所有令牌都作为数组返回。规则似乎是,如果令牌不是变量,而是特定的常量字符串,则它将作为字符串而不是数组返回。你不会得到行号。对于大括号("{", "}")、圆括号("(",")")、方括号("[","]")、逗号(",")、分号(";")以及一大堆运算符符号("!","=","+","*","/",".","+=",...)就是这样。
kevin at metalaxe dot com
16 年前
Rogier,感谢你的修正。此错误在 php 5.2.5 中仍然存在。但我注意到你的代码可能会弹出通知。更改此行

$temp[] = $tokens[0][2];

以读取此内容

$temp[] = isset($tokens[0][2])?$tokens[0][2]:'unknown';

修复了此通知。
rogier
16 年前
对以下代码的补充说明
请注意,只有前 2 个(或 3 个,如果需要)数组元素将被更新。

因为我只在 T_OPEN_TAG 的第一次出现时遇到了不正确的结果,所以我写了这个快速修复。
任何后续的 T_OPEN_TAG 在我的测试系统(Apache 2.0.52,PHP 5.0.3)上都被正确解析。

所以,此函数假设只有第一个 T_OPEN_TAG 可能不正确。
此外,此函数假设令牌数组的第一个元素(并且只有第一个元素)是可能不正确的令牌。
这实际上转化为令牌化源的第一个字符是 php 脚本开始标签 '<' 的开始,后面跟着 'php' 或 '%'(ASP 风格)
To Top