PHP Tokenizer组件实例详解

在某个项目中需要分析 PHP 代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这使用正则也可以实现,但无论从效率还是代码复杂度方面考虑,这都不是最优的方式。查询了 PHP 手册,发现其实 PHP 已经内置解析器的接口,那就是 PHP Tokenizer ,这工具正是我想要的。使用 PHP Tokenizer 能简单、高效、准确的分析出 PHP 源代码的组成。

实例

官方站点对 Tokenizer 的文档很少,不过这不影响我们理解它。Tokenizer 组件仅仅包含两个函数: tokengetall 以及 token_name ,它们分别用于分析 PHP 代码以及获取代码对应的标识符名称。

下面是个简单的实例,说明如何使用这两个函数:

  1. $code = '<?php echo "string1"."string2"; ?>'
  2. $tokens = token_get_all($code); 
  3. foreach ($tokens as $token) { 
  4.     if (is_array($token)) { 
  5.         // 行号、标识符字面量、对应内容 
  6.         printf("%d - %s\t%s\n"$token[2], token_name($token[0]), $token[1]); 
  7.     } 

对应的输出为

  1. 1 - T_OPEN_TAG    <?php  
  2. 1 - T_ECHO    echo 
  3. 1 - T_WHITESPACE      
  4. 1 - T_CONSTANT_ENCAPSED_STRING    "string1" 
  5. 1 - T_CONSTANT_ENCAPSED_STRING    "string2" 
  6. 1 - T_WHITESPACE      
  7. 1 - T_CLOSE_TAG    ?> 

这里顺便说明下,$token 如果为数组,那么分别对应的三个数组成员为 token 标识符(可以用 token_name 获得字面量)、对应的源代码内容、以及对应的行号。

还有中情况就是 $token 为字符串,这可能的情况之一就是为 TCONSTANTENCAPSED_STRING 等常量,在分析代码时要注意。如果对这点很在意,可以考虑使用 这里的代码 。

是的,调用方式非常的简单,我们的野心当然远远要比写个简单的循环要大得多。我们可以利用这个组件做写实事,例如下面的代码用于「压缩」 PHP 代码,去除不不要的换行、空白以及注释

  1. /** 
  2.  * PHP 源代码 
  3.  * 
  4.  */ 
  5. class CompactCode 
  6.     static protected $out
  7.     static protected $tokens
  8.     static public function compact($source
  9.     { 
  10.         // 解析 PHP 源代码 
  11.         self::$tokens = token_get_all($source);    
  12.         self::$out = ''
  13.         reset(self::$tokens); 
  14.         // 递归判断每个标记符的类型 
  15.         while ($t = current(self::$tokens)) { 
  16.             if (is_array($t)) { 
  17.                 // 过滤空白、注释 
  18.                 if ($t[0] == T_WHITESPACE || $t[0] == T_DOC_COMMENT || $t[0] == T_COMMENT) { 
  19.                     self::skipWhiteAndComments(); 
  20.                     continue
  21.                 }        
  22.                 self::$out .= $t[1]; 
  23.             } else { 
  24.                 self::$out .= $t
  25.             } 
  26.             next(self::$tokens); 
  27.         } 
  28.         return self::$out
  29.     } 
  30.     static private function skipWhiteAndComments() 
  31.     { 
  32.         // 增加个空格,用于分割关键字 
  33.         self::$out .= ' '
  34.         while ($t = current(self::$tokens)) { 
  35.             // 再次贪婪查找 
  36.             if (is_array($t) && ($t[0] == T_WHITESPACE || $t[0] == T_DOC_COMMENT || $t[0] == T_COMMENT)) { 
  37.                 next(self::$tokens); 
  38.             } else { 
  39.                 return
  40.             } 
  41.         } 
  42.     } 

调用方式很简单,只需要使用

  1. CompactCode::compact($source_code); 

即可,返回的字符串就是压缩以后的内容。

转载请注明:代码家园 » PHP Tokenizer组件实例详解

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)