【问题标题】:Automatically parsing PHP to separate PHP code from HTML自动解析 PHP 以将 PHP 代码与 HTML 分离
【发布时间】:2011-05-06 08:19:47
【问题描述】:

我正在开发一个大型 PHP 代码库;我想将 PHP 代码与 HTML 和 JavaScript 分开。 (我需要对 PHP 代码进行几次自动搜索和替换,在 HTML 上进行不同的搜索和替换,在 JS 上进行不同的搜索)。是否有一个好的解析器引擎可以为我分离出 PHP?我可以使用正则表达式来做到这一点,但它们并不完美。也许我可以在 ANTLR 中构建一些东西,但最好是现有的解决方案。

我应该明确表示:我不想要或不需要完整的 PHP 解析器。只需要知道给定的令牌是否是: - PHP代码 - PHP 单引号字符串 - PHP 双引号字符串 - PHP 评论 - 不是 PHP,而是 HTML/JavaScript

【问题讨论】:

  • 只是一个简短的说明。从您的列表中划掉正则表达式!
  • @Alin 我不太确定。看看我的回答为什么
  • 我不认为你可以为任何 PHP、HTML 或 JavaScript 构建正则表达式。也许对于其中的特定子集。

标签: php parsing code-generation antlr


【解决方案1】:

PHP 本身内置的tokenizer 怎么样?

tokenizer 函数提供了一个 PHP 标记器的接口 嵌入在 Zend 引擎中。使用 这些函数你可以自己写 PHP源码分析或修改 无需处理的工具 词汇上的语言规范 级别。

您在 cmets 中询问您是否可以从标记化的输出中重新生成代码 - 但是您可以,所有空格都保留为 T_WHITESPACE 标记。以下是将标记化的输出转换回代码的方法:

$regenerated='';

$tokens = token_get_all($code);
foreach($tokens as $idx=>$t)
{
    if (is_array($t))
    {

         //do something with string and comments here?
         switch($t[0])
         {
             case T_CONSTANT_ENCAPSED_STRING:
                  break;
             case T_COMMENT:
             case T_DOC_COMMENT:
                 break;

         }
         $regenerated.=$t[1];


    }
    else
    {
         $regenerated.=$t;
    }
}

【讨论】:

  • 如果我有令牌,如何重新生成源文本?用我原来的缩进和行距?用cmets?原程序员会接受结果吗?
  • 是的,空格和 cmets 被视为与任何其他标记一样 - 请参阅我的扩展答案,了解如何从标记化数据重建原始源。
【解决方案2】:

为了将 PHP 与其他 PHP 区分开来,PHP 的内置标记器是您的最佳选择:请参阅 token_get_all()

对于其余部分,您最好使用DOM parser。隔离<script> 部分(和外部脚本,甚至onXXXX 事件)很容易这样。

不过,从已解析的 DOM 树重新构建相同的文档可能会很困难 - 我想这取决于您需要对结果做什么以及原始 HTML 的干净程度。正则表达式(糟糕!)对于这部分可能会更好。

【讨论】:

    【解决方案3】:

    如果您只想检查标记,那么正如其他人所建议的那样,PHP 标记器可能是一个不错的选择。

    如果您想做的是以可靠的方式自动更改源代码,我不确定这会对您有所帮助。您将如何重新生成修改后的源文本?

    另一种方法是使用program transformation 引擎。这样的引擎可以将源文本解析为抽象语法树,捕获程序的结构(以及所有标记的有效内容),并允许使用可靠的模式匹配/转换来搜索和转换这些 AST。要做到这一点,您需要一个能够可靠解析 PHP 的引擎, 并且可以从更改的 AST 中重现可编译的源文本。

    我们的DMS Software Reengineering Toolkit就是这样一个程序转换系统,它有一个强大的PHP Front End,可以准确地处理PHP5,将结果解析、转换和漂亮地打印回文本。 (使 PHP 解析器正确困难,因为该语言的文档记录很差)。因为前端可以准确地提取 HTML 和 PHP 代码,所以不需要 分离出文本;它们将停在独特的树节点中清晰可辨的位置。

    要将所有回显的字符串从小写变为大写,您可以使用 DMS 解析 PHP,然后应用以下转换规则:

     rule uppercase_echoed_string(s: STRING): statement -> statement
     =   "echo \s;" ->  "echo \uppercase\(\s\);".
    

    此规则是用 DMS 的规则规范语言 (RSL) 编写的,这显然不是 PHP。引号里面的东西是PHP代码;这些是 meta 引号包裹在被操作的编程语言的文本周围。 \ 字符是元转义: \s 表示必须匹配字符串文字的元变量, \uppercase 是 RSL 语言外部的 DMS 函数的名称, ( ) 是元函数调用大写的元括号, 应用于匹配的字符串 \s。因为该规则在 AST 上运行,所以不能混淆;它不会更改 /* echo 'def' */ 的文本,因为那不是语句。

    您可能需要几个规则来处理各种语法组合:在这种情况下,STRING 指的是单引号的文字字符串;双引号字符串不是整体实体,而是由一系列 QUOTED_STRING_FRAGMENTS 组成,这些 QUOTED_STRING_FRAGMENTS 对应于双引号字符串内的 PHP 表达式之间的双引号字符串中的文本。

    在转换过程结束时,除了已应用转换的地方外,已更改的 AST 连同原始缩进和 cmets 一起发出。

    还有一个用于 DMS 的完全语言准确的 JavaScript 解析器,如果您想准确处理 SCRIPT 标记的内容,则需要它。

    如果您想对源代码进行可靠的更改,恕我直言,这是唯一的好方法。您可以尝试字符串破解和正则表达式,但解析 PHP 需要上下文无关的解析器,而 RE 不这样做,因此您得到的任何结果都不可信。

    【讨论】:

    • 非常有趣,艾拉。这当然是一种稳健的方法。具有讽刺意味的是,它可能遇到的一个困难是 PHP 代码被注释掉,但仍应修改(正则表达式黑客仍然会找到它......)。另外-您编写的“程序转换”链接是404ing。
    • @SRobertJames:如果您有代码,有时在 cmets 中,有时没有,您将无法做出可靠的更改。你怎么知道哪些 cmets 只是 cmets,哪些包含真实代码?如果你坚持混合这些,你可以考虑用标记编辑包含真实代码的 cmets,表明它们是真实代码;然后使用 DMS 您可以处理常规代码,对于 cmets,您可以检查标记并将 DMS 解析器应用于评论正文,进行更改,漂亮地打印 mod 并将它们放回 cmets。 (链接已修复,抱歉)。
    • @SRobertJames:这引发了一个问题,即为什么您注释掉了代码。如果要注释掉,最好将该代码放在由配置开关控制的条件中,例如 if feature7 { code } 。这为您提供了禁用代码的优势,通过设置功能开关启用,并且不必处理“此评论是否包含真实代码?”的歧义。
    猜你喜欢
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 2019-12-28
    • 2011-11-03
    • 2011-05-25
    • 1970-01-01
    相关资源
    最近更新 更多