PHP编码有很多工具,为我们带来很多便利,比如IDE、Debug工具,PHP单元测试工具等,对于CodeSniffer因为需要,有一定的研究,现在写出来,记录一下,以供以后需要。
工具简介
众所周知,统一的编码风格,不仅使你所写的代码清爽大气,也使无论是你本人,还是其他人,更容易阅读。那么一个统一的编码风格是怎么样的呢?他主要分为以 下几个方面,php标签、变量的命名、每一行的长度、缩进方式、控制语句以及函数的调用等等,具体的标准可以参考Expert PHP 5 Tools.pdf这本书的第一章,而对于我们团队来讲,也有自己的独有的风格,当前,Leapfrog中除了变量和函数命名方式与上书中第一章有所出入 外,其他的都是相同的。Leapfrog中使用的是下划线方式,zend一般采用驼峰方式。PHP_CodeSniffer能够自动检测你的源代码中的风 格为题,并给出具体的行号,告诉你这个与标准有什么出入,以提醒你改正。目前,该工具的安装环境是PHP version 5.1.2及以上。
工具的安装
使用 sudo pear install PHP_CodeSniffer-1.3.0 自动安装
工具的使用
Usage: phpcs [-nwlsapvi] [-d key[=value]]
[--report=<report>] [--report-file=<reportfile>] [--report-<report>=<reportfile>] ... [--report-width=<reportWidth>] [--generator=<generator>] [--tab-width=<tabWidth>] [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>] [--config-set key value] [--config-delete key] [--config-show] [--standard=<standard>] [--sniffs=<sniffs>] [--encoding=<encoding>] [--extensions=<extensions>] [--ignore=<patterns>] <file> ... -n Do not print warnings (shortcut for --warning-severity=0) -w Print both warnings and errors (on by default) -l Local directory only, no recursion -s Show sniff codes in all reports -a Run interactively -p Show progress of the run -v[v][v] Print verbose output -i Show a list of installed coding standards -d Set the [key] php.ini value to [value] or [true] if value is omitted --help Print this help message --version Print version information <file> One or more files and/or directories to check <extensions> A comma separated list of file extensions to check (only valid if checking a directory) <patterns> A comma separated list of patterns to ignore files and directories <encoding> The encoding of the files being checked (default is iso-8859-1) <sniffs> A comma separated list of sniff codes to limit the check to (all sniffs must be part of the specified standard) <severity> The minimum severity required to display an error or warning <standard> The name or path of the coding standard to use <tabWidth> The number of spaces each tab represents <generator> The name of a doc generator to use (forces doc generation instead of checking) <report> Print either the "full", "xml", "checkstyle", "csv", "emacs" "source", "summary", "svnblame" or "gitblame" report (the "full" report is printed by default) <reportfile> Write the report to the specified file path <reportWidth> How many columns wide screen reports should be printed
主要介绍的是,-i参数,用来显示当前的检测风格,系统(1.3.0)默认了PEAR, MySource, Zend, PHPCS and Squiz几种风格
$ phpcs --report=summary /path/to/code 以汇总的方式,报告错误
$ phpcs --standard=PEAR /path/to/code/myfile.inc 指定以特定的标准检测
$ phpcs --extensions=php /path/to/code 仅仅检测php后缀文件
$ phpcs --config-set default_standard Squiz 设置默认值
忽略某些文件和文件夹的方法,有时候,我们要检测一个工程,但是呢,有时候因为文件太久,我们不想更改,而如果检测这些文件会带来很多问题这时候,我们可以选择忽略这些文件
$ phpcs --ignore=*/tests/*,*/data/* /path/to/code
所有的配置文件都写入了/home/renjun/php/lib/php/data/PHP_CodeSniffer/CodeSniffer.conf 因此要保证这个文件写权限,而且可以用vi进行编辑更改设置。 更多使用帮助请查看官方文档。
配置文件长什么样?
$phpCodeSnifferConfig = array ( 'default_standard' => 'Leapfrog', '--extensions' => 'php', '--ignore' => 'tools/,conf/config.inc.php', )
自定义风格
一般情况下,使用自带的几种风格就已经足够用,但是针对Leapfrog这种情况,我们需要一种自定义的方式来进行检测,否则,很多东西都要被报有问题,影响我们真正的寻找有问题的地方,而且很多时候,我们需要有一种自己的定义的风格方式,这就需要研究这个工具了。 要新建一个风格必须在/home/renjun/php/lib/php/PHP/CodeSniffer/Standards这样的路径下,依照已有的风格,建一个目录,目录中包含ruleset.xml和Sniffs目录。 前者是告诉系统,当前使用哪写检测规则,后者则是自定义过滤规则目录。打开ruleset.xml文件可以看到是这样的样子:
<?xml version="1.0"?> <ruleset name="Leapfrog">
<description>A coding standard based on an early Zend Framework coding standard. Note that this standard is out of date.</description>
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/> <rule ref="Generic.Functions.OpeningFunctionBraceBsdAllman"/>
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<rule ref="PEAR.Classes.ClassDeclaration"/>
<rule ref="PEAR.ControlStructures.ControlSignature"/> <rule ref="PEAR.Functions.ValidDefaultValue"/>
<rule ref="PEAR.WhiteSpace.ScopeClosingBrace"/>
<rule ref="Generic.Files.LineLength">
<properties> <property name="lineLimit" value="80"/>
<property name="absoluteLineLimit" value="120"/>
</properties> </rule> <rule ref="Generic.Files.LineEndings">
<properties> <property name="eolChar" value="\n"/> </properties>
</rule>
</ruleset>
name:描述当前的检测标准的名称 description:描述信息 rule则是具体的检测规则,我们可以复用已有的规则,这样我们可以省去很多工作。 例如 <rule ref="Generic.Functions.FunctionCallArgumentSpacing"/> 表示使用的是Generirc规则下面的.FunctionCallArgumentSpacing规则, 依据名称我们可以看出来,这是检测函数调用的时 候,参数与参数之间是否有空格用的。具体的文件在 /home/renjun/php/lib/php/PHP/CodeSniffer/Standards/Generic/Sniffs /Functions/FunctionCallArgumentSpacingSniff.php 下面我们看看这个文件。这个文件的命名规则,跟 rule中的必须对应。文件名必须是FunctionCallArgumentSpacing+Sniff,而这个文件中定义的类名称也是固定的,以下划 线分隔。并且必须是实现 PHP_CodeSniffer_Sniff接口的两个方法。
class Generic_Sniffs_Functions_FunctionCallArgumentSpacingSniff implements PHP_CodeSniffer_Sniff { public function register() { return array(T_STRING); } public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); $tokens = $phpcsFile->getTokens(); $functionName = $stackPtr; $ignoreTokens = PHP_CodeSniffer_Tokens::$emptyTokens; $ignoreTokens[] = T_BITWISE_AND; $functionKeyword = $phpcsFile->findPrevious($ignoreTokens, ($stackPtr - 1), null, true); if ($tokens[$functionKeyword]['code'] === T_FUNCTION || $tokens[$functionKeyword]['code'] === T_CLASS) { return; } $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($functionName + 1), null, true); if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { return; } $closeBracket = $tokens[$openBracket]['parenthesis_closer']; $nextSeperator = $openBracket; while (($nextSeperator = $phpcsFile->findNext(array(T_COMMA, T_VARIABLE), ($nextSeperator + 1), $closeBracket)) !== false) { $brackets = $tokens[$nextSeperator]['nested_parenthesis']; $lastBracket = array_pop($brackets); if ($lastBracket !== $closeBracket) { continue; }
我只摘取一部分,详细的阅读官方文档。具体的,我们必须实现接口的具体方法,并且实现两个方法, public function register()、 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr),前者返回要处理的token。首先解释一下token,一个token是一个数组记录的是当前行的元素,例如,行号、这一行中的内 容,例如 : Array( [0] = > 367 [1] = ><?php [2] = >1 367是T_OPEN_TAG的值,表示php的开标签,而<?php则是具体的内容,1表示行号。这样,我们就不难理解过滤规则的php文件中的 代码,其中涉及到api可以查阅参考资料中的官方文档。
其他功能
SVN Hook功能,可以在svn提交的时候进行检测,如果不符合标准,则不让通过。因为当前的Leapfrog比较复杂,难于严格的执行规则,可以在以后考虑。
检测部署
现在已经将检测的程序部署到了search041058.sqa.cm4机器上,适合Leapfrog风格,并且默认为使用Leapfrog进行检测,使用方法为 /home/renjun/php/bin/phpcs search.php 检测search.php文件 /home/renjun/php/bin/phpcs /home/renjun/leapfrog/ 检测目录 等等。。。。。 如果移植到其他机器上,只需要复制/home/renjun/php/lib/php/data/PHP_CodeSniffer/CodeSniffer.conf到相应的目录以及 /home/renjun/php/lib/php/PHP/CodeSniffer/Standards/Leapfrog/目录到特定目录。
参考资料
http://pear.php.net/manual/en/package.php.php-codesniffer.config-options.php
Expert PHP 5 Tools.pdf
去西溪湿地骑车去啊,这么好的天气