13161216443

您所在位置: 首頁> 學習課程> PHP培訓 | 探究PHP_CodeSniffer的代碼靜態分析原理

PHP培訓 | 探究PHP_CodeSniffer的代碼靜態分析原理

發布百知教育 來源:學習課程 2019-11-15

使用PHP_CodeSniffer定制規則

在了解了詞法分析的原理后(探究PHP_CodeSniffer的代碼靜態分析原理(一)),我們現在嘗試使用PHP_CodeSniffer定制一條簡單的規則——“禁止使用#號進行單行注釋”。


有問題的測試代碼:

<?php
# Check for valid contents.
if ($obj->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的內容如下:

<?xml version="1.0"?>
<ruleset name="FireLine">
 <description>360 FireLine rule for test.</description>
</ruleset>

里面定義了規則庫的名稱和描述。

3. 創建規則實現文件

然后在Sniffs文件夾中新建Commenting文件夾,代表了一個更細的注解分類,接著這個文件夾里面新建php文件DisallowHashCommentsSniff.php(每個規則實現文件對應一個Sniff結尾的php文件),規則實現的內容如下:

<?php
/**
 * This sniff prohibits the use of Perl style hash comments.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Your Name <you@domain.net>
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */


namespace 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 array(int)
     */

    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 void
     */

    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/FireLine
D:/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"?>
<phpcs version="3.3.1">
xml version="1.0" encoding="UTF-8"?>
<file name="D:\git\PHP_CodeSniffer\src\Standards\FireLine\Tests\Commenting\test01.php" errors="3" warnings="0" fixable="0">
    <error line="3" column="1" source="FireLine.Commenting.DisallowHashComments.Found" severity="5" fixable="0">禁止使用#號進行注釋;掃描發現 # Check for valid contents.</error>
    <error line="7" column="5" source="FireLine.Commenting.DisallowHashComments.Found" severity="5" fixable="0">禁止使用#號進行注釋;掃描發現 # Value needs to be an array.</error>
    <error line="9" column="9" source="FireLine.Commenting.DisallowHashComments.Found" severity="5" fixable="0">禁止使用#號進行注釋;掃描發現 # Error.</error>
</file>
</phpcs>

從報告中可以看到,之前準備測試代碼文件中的三處錯誤,都能成功檢查出來。


注釋:本文內容來自公眾號 Qtest之道


PHP培訓:http://www.onhairsalon.com/php2019





上一篇:python培訓 | 本科學歷上python培訓班,好找工作嗎?

下一篇:應屆生去公司找個Java程序員的職位需要什么技能?

相關推薦

www.onhairsalon.com

有位老師想和您聊一聊

關閉

立即申請