探究PHP_CodeSniffer的代码静态分析原理(一)

PHP_CodeSniffer是一个用来检查PHP代码规范的开源项目。它主要通过词法分析的方式将PHP源码解析成TOKEN数组,然后在TOKEN中标记出不符合代码规范的代码位置。

今天,我们就一起来探究一下PHP_CodeSniffer的代码静态分析的原理。但在开始之前,需要先科普一些知识,便于后续的理解。

目前编程语言可以分为两大类:

第一类是像C/C++, .NET, Java之类的编译型语言, 它们的共性是: 运行之前必须对源代码进行编译,然后运行编译后的目标文件。

以Java举例,第一类编译的过程都是先进行词法分析、语法分析,然后才是编译。在经过语法分析之后,有一个抽象语法树(AST)的概念,算是语法分析的产出,之后的编译过程是编译器在AST基础上进行的。

第二类比如:PHP, Javascript, Ruby, Python这些解释型语言, 他们都无需经过编译即可”运行”,虽然可以理解为直接运行,但它们并不是真的直接就被能被机器理解, 机器只能理解机器语言,那这些语言是怎么被执行的呢, 一般这些语言都需要一个解释器, 由解释器来执行这些源码, 实际上这些语言还是会经过编译环节, 只不过它们一般会在运行的时候实时进行编译。

以PHP举例,PHP的运行过程是怎样的呢?

传递给php程序需要执行的文件, php程序完成基本的准备工作后启动PHP及Zend引擎, 加载注册的扩展模块。

初始化完成后读取脚本文件,Zend引擎对脚本文件进行词法分析,语法分析。然后编译成opcode执行。 如果安装了apc之类的opcode缓存, 编译环节可能会被跳过而直接从缓存中读取opcode执行。

TOKEN

在文章开头,我们已经知道PHP_CodeSniffer的主要原理是将PHP源码解析成TOKEN数组,同时在PHP_CodeSniffer源码中,很多操作的核心就围绕着TOKEN展开。

那么问题来了,TOKEN是什么?

PHP词法解析器在解析PHP语言的过程中,PHP 语言的不同部分在内部被表示为类似T_XXX 的类型,这个T_XXX的类型就叫TOKEN,也叫标识符~

标识符部分列表:

PHP官网共119个标识符

在PHP中提供了token_get_all(string $source)方法解析提供的 source 源码字符,然后使用 Zend引擎的词法分析器获取源码中的 PHP 语言的TOKEN代号,就是上文中的T_XXX。TOKEN代号都有对应的唯一值,比如T_ABSTRACT对应的是312,是之前定义好的。你也可以使用PHP自带的token_name(312)方法获取TOKEN代号,示例代码如下:

我们现在已经了解了PHP源码通过词法解析器解析后会变成TOKEN形态,但是这个词法解析的详细过程是怎样的呢?

PHP词法分析

在了解了TOKEN之后,就得详细了解一下词法分析了。词法分析就是从输入流里边一个字符一个字符的扫描,识别出对应的词素,最后把源文件转换成为一个TOKEN序列。以最简单的一行代码举例词法分析的流程:

在Zend引擎中,当扫描到”

我们已经进入了PHP脚本解析的状态了。在词法解析器扫描字符的过程中,需要记录扫描过程的各

个参数以及当前状态,这些变量都是以yy开头命名。常用到的就是:yy_state, yy_text, yyleng,

yy_cursor, yy_limit。

扫描 echo 前:

扫描 echo 后:

通过一个字符一个字符的扫描最终会得到一个TOKEN序列。我们来使用上文提到的PHP自带的 token_get_all() 方法来进行词法分析,查看这个TOKEN序列:

运行该文件后,输出结果:

从结果中看出序列里每一个TOKEN也是一个数组。在每个TOKEN数组中,第一个索引是TOKEN的唯一值,第二个索引默认是对应的代码,如果TOKEN不存在对应代码,那么代表所在行数的第三个索引会自动挪到第二个索引位置。我们继续来探究第一个索引的唯一值,通过token_name()方法来查看对应的TOKEN代号。

输出为:

结合这个TOKEN代号对应的语法以及TOKEN序列的输出,我们就能理解刚才那行代码词法分析后的TOKEN序列内容,并且能根据序列内容还原源代码。所以,只要有词法分析后的TOKEN序列内容,我们就可以结合我们自己的需求,在TOKEN序列内容的基础上进行PHP_CodeSniffer规则的定制。敬请关注下篇文章,结合原理教你如何自定义规则。

参考文章:

深入理解PHP内核:

http://www.php-internals.com/book/?p=chapt01/01-02-code-structure

PHP­Zend引擎剖析:

https://blog.csdn.net/raphealguo/article/details/16941531

Qtest是360旗下的专业测试团队!

是WEB平台部测试技术平台化、效率化的先锋力量!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181113B1SOHR00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券