PHP Conference Japan 2024

token_get_all

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

token_get_all将给定的源代码分割成PHP标记

描述

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条笔记

来自 basnetworks.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();

// 获取所有token
$tokens = token_get_all($source);

// 将换行符拆分成独立的token
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")
{
// 这是一个换行符token
$new_tokens[] = array(T_NEW_LINE, $data);
}
else
{
// 使用原始token名称添加token
$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模式。

为了等待更高的稳定性,`token_get_all()`只用于PHP代码(而不是混合的HTML)
首先完全提取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
6年前
注意:使用TOKEN_PARSE处理无效的php文件时,可能会出现如下错误
解析错误:语法错误,意外的'__construct'(T_STRING),预期函数(T_FUNCTION)或常量(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年前
并非所有标记都作为数组返回。规则似乎是,如果标记不是变量,而是一个特定的常量字符串,则将其作为字符串返回。你得不到行号。对于大括号("{", "}")、括号("(", ")")、方括号("[", "]")、逗号(",")、分号(";")以及大量运算符符号("!", "=", "+", "*", "/", ".", "+=", ...) 都是如此。
To Top