有没有用PHP编写的像样的PHP解析器?

83

我经常处理和分析PHP代码。通常我只使用Tokenizer来完成这项工作。对于大多数应用程序而言,这已经足够了。但有时候仅仅使用词法分析器解析是不够可靠的(显然)。

因此,我正在寻找一些用PHP编写的PHP解析器。我发现了hnw/PhpParserkumatch/stagehand-php-parser。它们都是通过将zend_language_parser.y自动转换为一个PHP文件的.y文件(然后编译成LALR(1)解析器)创建的。但是这种自动转换无法使用。

那么,有没有像样的用PHP编写的PHP解析器呢?(我需要一个PHP 5.2版本和一个PHP 5.3版本。但其中任何一个都是一个很好的起点。)


3
@Charles:我会用这个工具来处理许多事情,只要需要将PHP源代码转换为AST表示的任何内容 ;) - NikiC
2
我认为你不会在PHP中找到任何大规模、强大的语言解析器。因为没有这方面的需求。 - Ira Baxter
1
你应该在周末编写一个代码。 - markwatson
4
过去一周,我自己编写了一个解析器的初始版本:https://github.com/nikic/PHP-Parser。我对它进行了与我的代码库的测试,结果表现良好。接下来,我将继续改进接口,以使其更易用。 - NikiC
1
我差点向你推荐了你自己的项目。 - jeteon
显示剩余4条评论
5个回答

135

在这里找不到完整稳定的解析器之后,我决定自己编写一个。以下是结果:

PHP-Parser:一个用PHP编写的PHP解析器

该项目支持解析任何PHP版本(从PHP 5.2到PHP 8.1)的代码。

除了解析器本身外,库还提供了一些相关组件:

  • 将AST编译回PHP(“pretty printing”)
  • 用于遍历和更改AST的基础设施
  • 序列化和反序列化为XML(以及以人类可读的形式进行转储)
  • 将AST转换为JSON并返回
  • 解析命名空间名称(别名等)

有关用法概述,请参见"基本组件的用法"部分的文档


2
这太棒了!你有维护它的计划吗? - MikeSchinkel
1
@NikiC 谢谢你!那是一个很棒的库 :-) - BVengerov
2
哇,PHP 7.1 在2011年12月初就开始支持了! - dotancohen

11

这对您来说可能不是一个很好的选择,因为它违反了纯PHP约束,但:

一段时间以前,php-internals的成员决定将其解析技术切换到Lemon。在PHP svn repo中有一个包含所需更改的分支

他们决定不再继续使用它,因为他们发现Lemon解决方案稍微慢了10-15%。但是该分支仍然存在。

这里有一个作为PHP扩展编写的旧版Lemon解析器。您可以尝试使用它。还有这个PEAR包。还有另一个lemon软件包(通过这篇关于PGN的博客文章)。

当然,即使您让它正常工作,我也不确定您会对数据做什么,或者数据看起来像什么。

另一个疯狂的选择是查看Quercus,这是Java中的PHP实现。他们必须已经编写了解析器,也许值得调查一下。


首先,对于您的深入研究表示赞赏。主要问题不是没有办法在PHP中构建解析器。您已经提到了使用Lemon PHP语法和编译它。更简单的方法可能是使用“真正”的yacc/bison语法(也有编译器)。问题更多的是,将用于生成操作码的yacc C代码转换为用于生成AST的yacc PHP代码需要大量的工作量。因此,我正在寻找是否有人已经完成了这项工作。 - NikiC
@nikic 我认为至今没有人这样做的原因之一是,实际上并没有关于PHP是什么以及如何解析它的规范。php-internals曾经彻底拒绝了整个概念。因此,在PHP源代码之外,没有一个权威的来源来告诉我们如何实际进行解析。没有这个权威来源作为参考,构建正确的解析器将是一次真正的冒险。不幸的是,这意味着从yacc或Lemon数据开始可能是最好的选择。 - Charles
@nikic, Charles:对于我们的PHP解析器来说,这是一次真正的冒险。方法:提出词法分析器/语法,尝试数千个文件,出现错误,调整,再次尝试。需要大约一年的这样的努力才能为一个文档不完善的语言获得一个强大的解析器。至少对我们来说是这样。你的情况可能会有所不同,但差别不会太大。 - Ira Baxter

7

有AST,但没有针对“数学运算”的(我想您指的是“表达式”?这是语言的关键部分,特别是考虑到带有嵌入式表达式的双引号“字符串字面值”实际上只是复杂字符串表达式)。 - Ira Baxter
2
你获得了悬赏,因为这是最接近问题的答案。但显然它实际上并不可用,因为它缺少PHP语法的一半... - NikiC
这篇文章的内容已经过时了。虽然此后有积极的开发,但我不知道它对PHP语法的支持情况如何。 - nhahtdh

3
抱歉,这段内容不是用PHP编写的。构建这种类型的机器很难,而PHP并不特别适合语言处理任务。
我们的PHP前端提供完整的PHP 4.x和5.x(编辑于2016年9月:现在支持PHP 7)解析,自动构建具有完整PHP语法细节的AST,并且可以从AST生成可编译的源文本。考虑到所有奇怪的细节,包括奇怪的字符串文字、捕获的注释、基数数字等,这比听起来要难得多。
但是,AST远远不够(您已经观察到仅仅使用标记是远远不够的)。
它所构建的基础,DMS软件重工具包 提供了对AST的分析和任意转换的支持。它还可以一次读取大量文件,实现跨PHP文件的分析和转换。

1
作为对第一句话的回应:已经有解析器生成器可以从 yacc 语法(例如 kmyacc)生成解析器。也就是说,在 PHP 中构建它和在任何其他语言中构建它之间没有太大区别。你所要做的就是,“只需要”(讽刺意味)将 zend_language_parser.y 中的 C 代码替换为一些构建节点树的 PHP 代码即可。 - NikiC
关于其余的部分:我真的很想有一个PHP解决方案。但是如果(这似乎非常可能)没有类似的东西,我可能会使用其他东西。我已经在SO上多次听说过DMS,我会去看看它。 - NikiC
@ninkic:所有图灵机(包括PHP)都可以模拟其他所有图灵机,当然可以在PHP中构建它。但是a)只需构建解析器;我认为PHP解析器不是设计用于构建树而是用于提供PHP p-code生成器,而且我认为您会发现需要不同,并且b)人们反复犯下错误,假设如果他们有AST,则其他所有内容都很容易;他们之所以犯这个错误,主要是因为他们没有使用AST进行复杂操作的经验。我构建DMS是因为这种假设是错误的。 - Ira Baxter
1
a) 是的,PHP解析器不是为了构建解析树而设计的,它是为了构建操作码流而设计的。这就是为什么几乎不可能自动将Zend语言解析器转换为PHP的原因。b) 我可能是犯了这个错误的人之一 ;) 从许多复杂的操作已经可以通过纯令牌流完成这个事实中,我得出结论(在你的眼中是错误的吗?)使用AST会更容易和更稳定。 - NikiC
@nikic:编译器技术50年的经验教训是,每种程序表示都使某些事情变得容易。你可以仅在文本上进行一些程序操作。你可以在标记上做更多的工作。你可以在AST上做更多的工作。如果你有符号表、控制和数据流信息(图形)、变量别名数据(指向分析),你可以做真正有趣的事情。当你尝试进行复杂的代码生成时,你会发现这些都是非常有用的东西。 - Ira Baxter
@nikic:如果非常紧急,而且你超出了范围,可以尝试访问irc.freenode.com并询问#php或#zftalk或#cakephp等频道,也许至少能得到一些反馈。在这里只有120次浏览。祝好运。 - user285594

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接