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

网友投稿 578 2022-09-07

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

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

使用PHP_CodeSniffer定制规则

在了解了词法分析的原理后(​​探究PHP_CodeSniffer的代码静态分析原理(一)​​),我们现在尝试使用PHP_CodeSniffer定制一条简单的规则——“禁止使用#号进行单行注释”。 有问题的测试代码:

contentsAreValid($array)) { $value = $obj->getValue(); # Value needs to be an array. if (is_array($value) === false) { # Error. $obj->throwError(); exit(); }}?>

测试代码中有三处都使用了​​#​​号进行单行注释操作,这是不允许的。我们该如何使用PHP_CodeSniffer编写新规则呢?

1. 规则库目录介绍

首先PHP_CodeSniffer的所有规则都存放在​​/src/Standards/​​​目录下,默认该目录下已经有Generic、PEAR、PSR1、PSR2、PSR12、Squiz、Zend等目录,每一个目录其实就是一个规则库。如果想使用其中某一个规则库,例如PEAR规则库,运行时加入参数​​--standard=D:/git/PHP_CodeSniffer/src/Standards/PEAR​​,扫描时就会使用该规则库进行扫描。

2. 创建新规则库目录

我们在​​/src/Standards/​​​目录下新建一个文件夹,命名为​​FireLine​​​,即规则库名为​​FireLine​​​,然后在​​FireLine​​​文件夹中新建​​Sniffs​​文件夹和ruleset.xml文件。其中ruleset.xml的内容如下:

360 FireLine rule for test.

里面定义了规则库的名称和描述。

3. 创建规则实现文件

然后在​​Sniffs​​​文件夹中新建​​Commenting​​​文件夹,代表了一个更细的注解分类,接着这个文件夹里面新建php文件​​DisallowHashCommentsSniff.php​​(每个规则实现文件对应一个Sniff结尾的php文件),规则实现的内容如下:

* @license BSD Licence * @linknamespace PHP_CodeSniffer\Standards\FireLine\Sniffs\Commenting;use PHP_CodeSniffer\Sniffs\Sniff;use PHP_CodeSniffer\Files\File;class DisallowHashCommentsSniff implements Sniff{ /** * Returns the token types that this sniff is interested in. * * @return public function register() { return array(T_COMMENT); }//end register() /** * Processes this sniff, when one of its tokens is encountered. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The current file being checked. * @param int $stackPtr The position of the current token in the * stack passed in $tokens. * * @return public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); if ($tokens[$stackPtr]['content']{0} === '#') { $error = '禁止使用#号进行单行注释;扫描发现 %s'; $data = array(trim($tokens[$stackPtr]['content'])); $phpcsFile->addError($error, $stackPtr, 'Found', $data); } }//end process()}//end class

4. 规则实现详解

首先每个sniff类必须实现Sniff接口,该接口内有两个必须要实现的方法:register()和process()方法。

首先通过调用register()方法告诉PHP_CodeSniffer我们要检查编码标准哪些方面(也就是我们要查找哪些类型的TOKEN)。然后当词法解析引擎碰到这些TOKEN时就会调用process()方法来做进一步处理。

在该文件中,我们可以看到register()方法中是想查找T_COMMENT类型的TOKEN,通过PHP官网提供的TOKEN列表中得到T_COMMENT对应的PHP语法为​​// 或 #,以及 PHP 5 下的 /* */​​,即PHP语法中的单行注释。所以说,当词法解析引擎遇到单行注释类别的TOKEN时,就会自动继续调用process()方法。

我们接着来看process()方法,该方法有两个参数,第一个是​​$phpcsFile​​​对象,即当前正在被处理的代码文件对象;第二个是​​$stackPtr​​​参数,这个参数的意思是我们当前关注的TOKEN-即代表着单行注释的TOKEN(T_COMMENT)在TOKEN序列中的索引。这里正好回应了上篇文章提到的PHP词法分析原理,将PHP源文件解析成一个TOKEN序列,而​​$stackPtr​​参数表示当前TOKEN在这个TOKEN序列的索引位置。

接下来是process()方法内的实现,首先通过PHP_CodeSniffer封装的​​getTokens()​​​方法来获得当前文件的TOKEN序列。在通过索引获取到我关注的T_COMMENT对应的TOKEN后,进一步获取TOKEN数组里面的​​content​​索引对应的内容。

TOKEN数组里面包含了​​code、type、content​​​这三种索引,分别对应的内容是​​TOKEN代号唯一值、TOKEN代号即T_COMMENT、TOKEN所对应的代码​​​。所以判断条件里面的​​$tokens[$stackPtr]['content']{0}​​​的意思是取TOKEN序列中我们所关注的T_COMMENT对应的TOKEN,然后取这个TOKEN中对应的代码中的第一个字符。如果这个字符是​​#​​​,说明触发了单行注释禁止使用​​#​​号的规则。我们最后通过addError()方法来记录触发规则的TOKEN和对应的代码,以及我们的规则解释。

5. 规则运行

规则实现完成后,我们运行一下看一下效果:

php D:/git/PHP_CodeSniffer/bin/phpcs--standard=D:/git/PHP_CodeSniffer/src/Standards/FireLineD:/git/PHP_CodeSniffer/src/Standards/FireLine/Tests--report=xml --report-file=E:/RedlineReport/php_report01.xml

其中​​--standard​​​参数就是指定运行我们自定义的FireLine规则库。 ​​​D:/git/PHP_CodeSniffer/src/Standards/FireLine/Tests​​目录中存放了有问题的测试代码文件。 最后生成的XML报告文件内容:

xml version="1.0" encoding="UTF-8"?> 禁止使用#号进行注释;扫描发现 # Check for valid contents. 禁止使用#号进行注释;扫描发现 # Value needs to be an array. 禁止使用#号进行注释;扫描发现 # Error.

从报告中可以看到,之前准备测试代码文件中的三处错误,都能成功检查出来。

参考文章: Coding Standard Tutorial

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

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:1260. 二维网格迁移 : 简单构造模拟题
下一篇:Mysql在大型网站的应用架构演变(mysql的基本架构)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~