安装插件
composer require squizlabs/php_codesniffer --dev
composer require brainmaestro/composer-git-hooks:* --dev
运行测试
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin# ./vendor/bin/phpcs --standard=PSR1,PSR2 app/ routes/ config/
自定义校验规则
#vim _php_codesniffer.xml
<?xml version="1.0"?>
<ruleset name="custom">
<description>The custom coding standard.</description>
<!--
See the [documented coding standard](http://symfony.com/doc/current/contributing/code/standards.html)
This CodeSniffer standard does not yet enforce the following:
# Structure
* Declare class properties before methods;
* Declare public methods first, then protected ones and finally private ones.
* Use namespaces for all classes;
* Add PHPDoc blocks for all classes, methods, and functions;
* The @package and @subpackage annotations are not used.
* Use uppercase strings for constants with words separated with underscores
# Naming Conventions
* Use underscores for option, argument, parameter names;
-->
<!-- 文件 -->
<!-- 所有 PHP 文件都必须使用 UTF-8 编码,文件头不允许出现 BOM 标记。 -->
<rule ref="Generic.Files.ByteOrderMark"/>
<!-- 所有 PHP 文件都必须使用 Unix LF 格式作为行的结尾。 -->
<rule ref="Generic.Files.LineEndings">
<properties>
<property name="eolChar" value="\n"/>
</properties>
</rule>
<!-- 在只包含有 PHP 代码的文件中不允许使用 ?> 作为结束标签。 -->
<rule ref="Zend.Files.ClosingTag"/>
<!-- 不允许使用short tag"<?"开头,必须使用"<?php"开头. -->
<rule ref="Generic.PHP.DisallowShortOpenTag"/>
<!-- 缩进 -->
<!-- 代码缩进统一为 4 个空格,不允许使用 tab。 -->
<rule ref="Generic.WhiteSpace.ScopeIndent">
<exclude name="Generic.WhiteSpace.ScopeIndent.Incorrect" />
<exclude name="Generic.WhiteSpace.ScopeIndent.IncorrectExact" />
</rule>
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
<!-- 行 -->
<!-- 在非空行的结尾不允许出现尾随空白 -->
<rule ref="Squiz.WhiteSpace.SemicolonSpacing"/>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
<properties>
<property name="ignoreBlankLines" value="true"/>
</properties>
<exclude-pattern>*/app/Facades/*</exclude-pattern>
<exclude-pattern>*/app/Exceptions/*</exclude-pattern>
<exclude-pattern>*/app/Console/Kernel.php</exclude-pattern>
<exclude-pattern>*/bootstrap/*</exclude-pattern>
</rule>
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.StartFile">
<severity>0</severity>
</rule>
<!-- 每一行代码只允许一条语句。 -->
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
<!-- 方法与方法之间,都至少有一个空行。 -->
<rule ref="Squiz.WhiteSpace.FunctionSpacing">
<properties>
<property name="spacing" value="1"/>
</properties>
<exclude name="Squiz.WhiteSpace.FunctionSpacing.AfterLast" />
<exclude name="Squiz.WhiteSpace.FunctionSpacing.BeforeFirst" />
</rule>
<!-- PHP 关键字 和 true/false/null -->
<!-- PHP关键字必须使用小写。 -->
<rule ref="Generic.PHP.LowerCaseKeyword" />
<!-- 关键字 true, false 和 null 必须使用小写。 -->
<rule ref="Generic.PHP.LowerCaseConstant"/>
<!-- =、=> 等操作符的前后都必须有一个空格 -->
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
<exclude name="Squiz.WhiteSpace.OperatorSpacing.SpacingAfter" />
</rule>
<!-- 字符串 -->
<!-- 不允许对两个不带变量的字符串使用连接符,应该用一个字符串表示. -->
<rule ref="Generic.Strings.UnnecessaryStringConcat"/>
<!-- 注释 -->
<!-- 每个函数/方法必须有文字描述 -->
<rule ref="PEAR.Commenting.FunctionComment">
<exclude-pattern>*/app/Console/Kernel.php</exclude-pattern>
<exclude-pattern>*/app/Exceptions/*</exclude-pattern>
<exclude-pattern>*/app/Facades/*</exclude-pattern>
<exclude name="PEAR.Commenting.FunctionComment.MissingReturn" />
<exclude name="PEAR.Commenting.FunctionComment.MissingParamComment" />
<exclude name="PEAR.Commenting.FunctionComment.SpacingAfterParamType" />
<exclude name="PEAR.Commenting.FunctionComment.SpacingAfterParamName" />
<exclude name="PEAR.Commenting.FunctionComment.ExtraParamComment" />
</rule>
<!-- 命名空间(namespace)和 use 关键字的使用 -->
<!-- 在 use 定义块之后必须有一个空行 -->
<rule ref="PSR2.Namespaces.UseDeclaration">
<exclude-pattern>*/app/Models/*</exclude-pattern>
</rule>
<!-- 类、类属性和类方法 -->
<!-- 类、接口和特征的名称必须以大写开头,如:PartnerInfo、Partner_Info -->
<rule ref="Squiz.Classes.ValidClassName"/>
<rule ref="Squiz.Functions.LowercaseFunctionKeywords"/>
<!-- 一个文件中只能包含类、接口和特征中的一个,不允许出现多个. -->
<rule ref="Generic.Files.OneClassPerFile"/>
<!-- 一个文件中只能包含类、接口和特征中的一个,不允许出现多个. -->
<rule ref="Generic.Files.OneInterfacePerFile"/>
<!-- 类常量 -->
<!-- 类的常量定义必须全部为大写,并用下划线分割每个单词,如:BRAND_DRAFT、BRAND_DELETED -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName"/>
<!-- 函数定义 -->
<rule ref="Squiz.Functions.FunctionDeclaration"/>
<rule ref="Squiz.NamingConventions.ValidFunctionName">
<exclude name="Squiz.NamingConventions.ValidFunctionName.PrivateNoUnderscore" />
</rule>
<!-- 函数参数 -->
<!--
在参数队列中,逗号之前不允许出现空格,逗号之后必须有一个空格。
在方法的参数队列中定义带默认值的参数时,必须放到队列的末尾。
参数队列可以被写到多行,每一行都需要用一个同样的缩进,
第一个参数必须被写到新的一行,并且每一行只能有一个参数。
当参数队列被写到多行时,结束括号和开始大括号必须被写到一行,两者之间必须有一个空格。
-->
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">
<properties>
<property name="equalsSpacing" value="1"/>
</properties>
</rule>
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint">
<severity>0</severity>
</rule>
<!-- 类方法和一般函数(function)的调用 -->
<!--
当调用一个类方法或者一般函数时,方法或函数名称和开始括号之间不允许出现空格,
在开始括号之后和结束括号之前都不允许出现空格。
在参数队列里,逗号之前不允许出现空格,逗号之后必须有一个空格。
参数队列可以被写到多行,每一行都需要用一个同样的缩进,
第一个参数必须被写到新的一行,并且每一行只能有一个参数。
-->
<rule ref="PEAR.WhiteSpace.ObjectOperatorIndent"/>
<rule ref="PEAR.Functions.FunctionCallSignature">
<exclude name="PEAR.Functions.FunctionCallSignature.Indent"/>
<exclude name="PEAR.Functions.FunctionCallSignature.CloseBracketLine"/>
<exclude name="PEAR.Functions.FunctionCallSignature.ContentAfterOpenBracket"/>
</rule>
<!-- 控制结构 -->
<!--
控制结构的一般样式规则如下:
在控制结构的关键字后面必须有一个空格
开始括号之后不能出现空格
结束括号之前不能出现空格
在结束括号和开始大括号之间必须有一个空格
代码块(结构体)必须有一个缩进
结束大括号必须在代码块结束后的下一行
每个代码块必须被封装到一个大括号内,以标准化代码结构,同时减少在添加代码时间引入错误的可能性。
-->
<rule ref="Squiz.ControlStructures.ControlSignature"/>
<!-- 必须用 elseif 代替 else if,让控制关键字看上去是一个单词,同时避免出现代码块逻辑错误。 -->
<rule ref="PSR2.ControlStructures.ElseIfDeclaration"/>
</ruleset>
# -s 参数会显示生效的规则,便于调试。
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin# ./vendor/bin/phpcs --standard=./_php_codesniffer.xml -s app/
FILE: /var/www/ogenes/Genes-Admin/app/Providers/MD5HashServiceProvider.php
----------------------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------------------------------------
32 | ERROR | Missing doc comment for function provides()
| | (PEAR.Commenting.FunctionComment.Missing)
----------------------------------------------------------------------------------------------------
Time: 207ms; Memory: 10MB
基于git修改的文件检测,同时支持docker
#vim php_codesniffer
#!/usr/bin/env bash
appPath=ogenes/Genes-Admin
phpversion=php81
hasError=false
[ -z ${DOCKER_LNMP+x} ]&&DOCKER_LNMP=N
CHANGE_FILES=$(git diff --name-only --diff-filter=ACM | grep -E '\.(php|phtml)$')
for cf in ${CHANGE_FILES[@]}
do
if [ $DOCKER_LNMP = "Y" ]; then
ret=`docker exec $phpversion bash -c \
"cd $appPath; ./vendor/bin/$1 --standard=./_php_codesniffer.xml $cf"`
else
ret=`$phpversion ./vendor/bin/$1 --standard=./_php_codesniffer.xml $cf`
fi
if [ -n "$ret" ];then
echo "${ret}"
fi
tmpError=`echo $ret| grep -E 'FOUND [1-9]+ ERROR'`
if [ -n "$tmpError" ]; then
hasError=true
fi
done
if $hasError
then
exit 1
else
echo 'Success!'
exit 0
fi
加入composer 命令
修改 composer.json
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"php81 ./vendor/bin/cghooks update",
"php81 ./vendor/bin/phpcs --config-set php_version 80108",
"php81 ./vendor/bin/phpcs --config-set colors 1",
"php81 ./vendor/bin/phpcs --config-set encoding utf-8"
],
………………
………………
"lint": "./php_codesniffer phpcs",
"lint-fix": "./php_codesniffer phpcbf"
},
composer update
测试
#随便修改 AuthController.php 一行代码
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin# composer run lint
> ./php_codesniffer phpcs
FILE: /var/www/ogenes/Genes-Admin/app/Http/Controllers/User/AuthController.php
------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 4 LINES
------------------------------------------------------------------------------
12 | ERROR | [ ] Missing doc comment for function login()
34 | ERROR | [x] Expected 1 blank line after function; 0 found
35 | ERROR | [ ] Missing doc comment for function logout()
44 | ERROR | [ ] Missing doc comment for function userinfo()
------------------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
------------------------------------------------------------------------------
Time: 122ms; Memory: 10MB
Script ./php_codesniffer phpcs handling the lint event returned with error code 1
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin#
加上钩子,pre-commit强制检测
"extra": {
"laravel": {
"dont-discover": []
},
"hooks": {
"pre-commit": [
"echo committing as $(git config user.name).",
"composer run lint"
]
}
},
composer update
提交测试
#docker环境中,在宿主机
➜ Genes-Admin git:(ogenes) ✗ export DOCKER_LNMP=Y
➜ Genes-Admin git:(ogenes) ✗ git add .
➜ Genes-Admin git:(ogenes) ✗ git commit -m '代码风格检测'
committing as 易怀源.
> ./php_codesniffer phpcs
FILE: .../ogenes/Genes-Admin/app/Http/Controllers/User/AuthController.php
----------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 4 LINES
----------------------------------------------------------------------
12 | ERROR | [ ] Missing doc comment for function login()
34 | ERROR | [x] Expected 1 blank line after function; 0 found
35 | ERROR | [ ] Missing doc comment for function logout()
44 | ERROR | [ ] Missing doc comment for function userinfo()
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------
Time: 133ms; Memory: 10MB
Script ./php_codesniffer phpcs handling the lint event returned with error code 1
#自动修正
➜ Genes-Admin git:(ogenes) ✗ composer run lint-fix
> ./php_codesniffer phpcbf
PHPCBF RESULT SUMMARY
----------------------------------------------------------------------
FILE FIXED REMAINING
----------------------------------------------------------------------
...dmin/app/Http/Controllers/User/AuthController.php 1 3
----------------------------------------------------------------------
A TOTAL OF 1 ERROR WERE FIXED IN 1 FILE
----------------------------------------------------------------------
Time: 192ms; Memory: 10MB
Success!
#无法自动修正的手动修正
#然后测试
➜ Genes-Admin git:(ogenes) ✗ git add .
➜ Genes-Admin git:(ogenes) ✗ git commit -m '代码风格检测'
committing as 易怀源.
> ./php_codesniffer phpcs
Success!
[ogenes 1941357] 代码风格检测
5 files changed, 458 insertions(+), 74 deletions(-)
create mode 100644 _php_codesniffer.xml
create mode 100755 php_codesniffer
修正历史提交的文件
#自动修正
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin# ./vendor/bin/phpcbf --standard=./_php_codesniffer.xml app config routes
#手动修正
root@d92a8d4c6792:/var/www/ogenes/Genes-Admin# ./vendor/bin/phpcs --standard=./_php_codesniffer.xml -s app config routes