代码规范扫描工具开发小记(1)
Wednesday, December 30th, 2009虽然有像 PHP_CodeSniffer 这样的解决方案,但是我还是坚持要写一个简单的,不依赖PEAR的代码规范扫描工具,这个工具和 PHP_CodeSniffer 最主要的区别是,PHP_CodeSniffer 使用无比复杂的 token_get_all() 函数,而这个工具使用正则扫描,具有更好的性能和更好的可维护性。
该扫描工具包含三个部分,(1)对代码规范的扫描(2)对缩进的扫描(3)对注释的扫描,可以对不符合规则的扫描结果提供修改的参考信息,这里讲到的是对(1)代码规范的扫描的开发小记:
用正则处理扫描的时候,有的代码规范无法实现,比如“用来分割函数参数的逗号后面必须有一个空格”这个代码规则,就很难实现:
functionName('arg1,arg1','arg2') // 错误
functionName('arg1,arg1', 'arg2') // 正确
因为参数字符串中的逗号会成为扫描的干扰,无法实现正确的扫描。
解决方法是先去掉字符串中的内容,然后再判断代码规范,这个正则比较简单:
preg_replace("/'[^']*'|\"[^\"]*"/U", "", $str);
但是要考虑到字符串中有这样的情况:
'don\'t'
'don\\'t'
'don\\\'t'
'don\\\\'t'
如果是奇数个\,则'为字符串的组成部分,如果是偶数个的\\,则'为字符串的结尾符,这样这个正则就复杂了那么一点,但是依然可以实现:
preg_replace("/'.*((\\\\\\\\)+'|[^\\\\]')|\".*((\\\\\\\\)+\"|[^\\\\]\")/U", "", $str);
还要考虑到字符串跨行的现象,所以加上修正符 s:
preg_replace("/'.*((\\\\\\\\)+'|[^\\\\]')|\".*((\\\\\\\\)+\"|[^\\\\]\")/Us", "", $str);
夸行以后又出现一个问题,注释中的 ' 会产生干扰,比如:
// don't need to do anything.
这里的话唯一的解决方法是将注释一起去掉,因为字符串 "http://www.csphp.com" 和 // dont need " here 中的 " 和 // 会互相干扰,所以这个正则必须写这么长,不能分两次处理:
preg_replace("/'.*((\\\\\\\\)+'|[^\\\\]')|\".*((\\\\\\\\)+\"|[^\\\\]\")|(\t| )*\/\*.*\*\/|(\t| )*\/\/.*(?=\n)/Us", "", $str);
这样就解决了,其他还要考虑的是 # 注释符号和 Here document 的语法干扰。
在实际运用的时候,如果需要对替换的字符串或者注释进行内容检查,可以这样加回调函数:
preg_replace("'.*((\\\\\\\\)+'|[^\\\\]')|\".*((\\\\\\\\)+\"|[^\\\\]\")|(\t| )*\/\*.*\*\/|(\t| )*\/\/.*(?=\n)/Use", "\$this->replace('\\0')", $str);
我的replace方法是返回空字符串,如果有换行符,则返回多个换行符和空字符串:
{
if (!preg_match('/\n/', $value))
{
return "''";
}
else
{
$lineNum = count(preg_split('/\n/', $value));
for ($i = 0; $i < $lineNum; $i++)
{
$temp[] = "''";
}
return implode("\n", $temp);
}
}
在去掉了字符串和注释以后,对代码规范的扫描就非常方便了。