PHP代码规范落地

主要从原理,到实践,再到自定义(最佳实践),全面讲解 PHP 代码规范应该如何做。

PHP 规范化的3个方向:

语法层面,运行时层面,规范层面。

语法层面

这一层是最基础的层面,存在语法错误的代码应该在第一时间被发现。

php -l filename php 自带语法检测命令。

使用 https://github.com/overtrue/phplint ,提供更好的界面展示和更灵活的 CI 自定义功能,但其底层依然是使用 php -l 检测 php 语法:

https://github.com/overtrue/phplint/blob/8.0/src/Linter.php#L157

运行时层面

运行时错误代码 是指需要到真正运行的时候才能检测出问题的代码,这类问题没办法很好的检测,除你真的运行它。

58-1.png

规范层面

这一层是面向代码风格的,是我们关注的重点,一个好的开发,代码风格都是基于别人是否容易理解,自己后期回顾的可追溯性效率是否高效来编程。

目前,PHP 社区主要有3套编码风格。

php 代码解析器

解析器代号列表

解析php代码的扩展:https://www.php.net/manual/zh/ref.tokenizer.php

php --re tokenizer 内容只有一些代号常量和2个函数,token_get_all(string $resource),token_name(int $token)

<?php
/**
 * Created by
 * Author purelight
 * Date 2022/2/8
 * Time 9:14 上午
 */

$code = file_get_contents(__DIR__ . '/../src/Client.php');

$tokens = token_get_all($code);
foreach ($tokens as $token){
    if (is_array($token)){
        printf("%d - %s\t%s\n",$token[2],token_name($token[0]),$token[1]);
    }else{
        var_dump($token);
    }
}

有了这些基础,就可以去做代码规范分析了,但工作量依然很大,我们尽可能利用开源社区已有的轮子。

PHP_CodeSniffer

https://github.com/squizlabs/PHP_CodeSniffer

其提供2个命令:phpcs(代码规范分析),phpcbf(代码纠正)。

文档:https://github.com/squizlabs/PHP_CodeSniffer/wiki

A coding standard in PHP_CodeSniffer is a collection of sniff files.

The default coding standard used by PHP_CodeSniffer is the PEAR coding standard.

其默认采用 PEAR 编码规范,https://pear.php.net/manual/en/standards.php

更加直接的了解各种规范:

root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs -i
The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz and Zend
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=PSR1 --generator=HTML >> ./example/PSR1.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=PSR2 --generator=HTML >> ./example/PSR2.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=PSR12 --generator=HTML >> ./example/PSR12.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=Squiz --generator=HTML >> ./example/Squiz.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=Zend --generator=HTML >> ./example/Zend.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=PEAR --generator=HTML >> ./example/PEAR.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=MySource --generator=HTML >> ./example/MySource.html
root@7e9a7a3b23b1:/var/www/html/daishu/ulucu# ./vendor/bin/phpcs --standard=./DsStandard/ --generator=HTML >> ./example/DsStandard.html

PEAR 规范示例:

58-2.png

这些规范互相补充,也有交集,还有互相冲突的。

  • phpcs

    ./vendor/bin/phpcs src/Client.php

    ./vendor/bin/phpcs --report=summary src

    ./vendor/bin/phpcs --standard=PEAR,./DsStandard src/Client.php

    ./vendor/bin/phpcs -i

    ./vendor/bin/phpcs --standard=PEAR -e

    ./vendor/bin/phpcs --standard=./DsStandard -e

    ./vendor/bin/phpcs --standard=PEAR --sniffs=PEAR.Commenting.FileComment src/Client.php

    ./vendor/bin/phpcs --standard=PEAR --report=code src/Client.php

  • phpcbf

    ./vendor/bin/phpcs --report=diff src/Client.php
    --- src/Client.php

    ./vendor/bin/phpcbf src/Client.php

自定义规范

步骤:

mkdir ./DsStandard
cd DsStandard
vim ruleset.xml // 参考https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset
mkdir Sniffs
cd Sniffs
... // touch sniff files

完整手册:https://github.com/squizlabs/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial

限制变量必须是驼峰命名的sniff例子:
<?php

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;

/**
 * Created by
 * Author purelight
 * Date 2022/2/9
 * Time 9:36 上午
 */

class VariableCamelCaseSniff implements Sniff
{

    public function register()
    {
        return [
            T_VARIABLE
        ];
    }

    public function process(File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();
        $variableName = substr($tokens[$stackPtr]['content'],1);
        $rs = preg_match_all('/[a-z]+[a-z|A-Z]+/',$variableName,$matches);
        if ($rs !== 1 || $matches[0][0] !== $variableName){
            $error = '变量不是驼峰命名';
            $data = [ trim($tokens[$stackPtr]['content']) ];
            $phpcsFile->addError($error,$stackPtr,'Found',$data);
        }
    }
}

测试效果:

58-3.png

内置Standard

https://github.com/squizlabs/PHP_CodeSniffer/tree/master/src/Standards

可配置的规则细项

比如 PEAR 规定每行最多80个字符,我们可以在 ruleset.xml 自定义这个值,比如改到100,从而适应我们自己的需求。

https://github.com/squizlabs/PHP_CodeSniffer/wiki/Customisable-Sniff-Properties#genericfileslinelength

.phpcs.xml

每个项目根目录下创建此文件,配置上要检查的代码路径,规范选择等等,相当于配置 phpcs 命令的各种参数,在项目根目录直接运行 phpcs 就会采用该配置文件运行代码检查。

具体配置手册参考:

https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xml.dist

FAQ

https://github.com/squizlabs/PHP_CodeSniffer/wiki/FAQ

结合IDE PHPStorm

Preferences -> PHP -> Quality Tools -> 设置 PHP_CodeSniffer 安装目录

Editor -> Inspections -> Quality Tools -> 设置 PHP_CodeSniffer validation 规则

不同版本IDE具体操作不同,基本就是这两个步骤,推荐全局安装

使用效果:

当使用 PEAR 规范,违反注释规范时ide给出提示如下

58-4.png

当设定自定义规范 DsStandard ,违反驼峰命名规范时ide给出提示如下

58-5.png

修正后:

58-7.png

结合 Jenkins

1,Jenkins 安装 Violations 插件

2,项目配置,Build 运行 phpcs 生成 checkstyle 文件,例如:

/root/.composer/vendor/bin/phpcs --report=checkstyle --report-file=./checkstyle.xml --standard=Zend ./app/Services/Common

3,配置 violations:

58-8.png
58-9.png

4,Build 查看效果:

58-10.png

点击文件名查看具体不符合规范的代码:

58-11.png
58-12.png

修改相应代码(仅 StandardService.php)之后再次 Build ,查看到已经没有该文件的提示了:

58-13.png

只要检测到含有不符合规范的代码,phpcs 命令返回错误码非0,构建会失败!后续可视情况调整相关参数。

最佳实践

默认的规范是比较严格的,就算拿优秀的社区package来验证,也会有一大堆ERROR和WARNING,所以,结合已有规范,选择性地制定自己的规范才是最佳选择。

即在已有 Standard 下选择部分 Sniff ,然后添加我们自定义的 Sniff 。

58-6.png

重心就是维护 N 多个自定义的 Sniffs ,然后用 ruleset 去配置,形成 Standard 。

总结

我们从3个层面逐步解释了 PHP 代码规范应该如何做,重点讲述了规范层面,包括原理,工具,IDE,advanced usage,已经有能力灵活控制代码质量了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容