Clean Code PHP 代码简洁之道

介绍

来自Robert C. Martin的书Clean Code的软件工程原理, 适用于PHP。这不是样式指南。这是在PHP中生产可读,可重用和可重构软件的指南。

并非必须严格遵循本文中的每个原则,而且将被普遍接受的原则甚至更少。这些只是准则,仅此而已,但它们是由Clean Code的作者在多年的集体经验中整理而成的。

灵感来自clean-code-javascript

尽管许多开发人员仍然使用PHP 5,但本文中的大多数示例仅适用于PHP 7.1+。

【文章来源】:github.com/php-cpm/clean-code-php

变数

使用有意义且明显的变量名

坏:

$ymdstr = $moment->format('y-m-d');

好:

$currentDate = $moment->format('y-m-d');

对相同类型的变量使用相同的词汇表

坏:

getUserInfo();
getUserData();
getUserRecord();
getUserProfile();

好:

getUser();

使用可搜索的名称(第1部分)

我们将阅读比编写更多的代码。我们编写的代码具有可读性和可搜索性,这一点很重要。通过不命名最终对理解我们的程序有意义的变量,我们伤害了我们的读者。使您的名字可搜索。

坏:

// 448 ™ 干啥的?
$result = $serializer->serialize($data, 448);

好:

$json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

使用可搜索的名称(第2部分)

坏:

class User
{
    // 7 ™ 干啥的?
    public $access = 7;
}

// 4 ™ 干啥的?
if ($user->access & 4) {
    // ...
}

// 这里会发生什么?
$user->access ^= 2;

好:

class User
{
    public const ACCESS_READ = 1;
    public const ACCESS_CREATE = 2;
    public const ACCESS_UPDATE = 4;
    public const ACCESS_DELETE = 8;

    // 默认情况下用户 具有读、写和更新权限
    public $access = self::ACCESS_READ | self::ACCESS_CREATE | self::ACCESS_UPDATE;
}

if ($user->access & User::ACCESS_UPDATE) {
    // do edit ...
}

// 禁用创建权限
$user->access ^= User::ACCESS_CREATE;

使用解释变量

坏:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

saveCityZipCode($matches[1], $matches[2]);

不错:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

[, $city, $zipCode] = $matches;
saveCityZipCode($city, $zipCode);

好:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

saveCityZipCode($matches['city'], $matches['zipCode']);

避免嵌套得太深,过早返回(第1部分)

太多的if else语句通常会导致你的代码难以阅读,直白优于隐晦
坏:

function isShopOpen($day): bool
{
    if ($day) {
        if (is_string($day)) {
            $day = strtolower($day);
            if ($day === 'friday') {
                return true;
            } elseif ($day === 'saturday') {
                return true;
            } elseif ($day === 'sunday') {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

好:

function isShopOpen(string $day): bool
{
    if (empty($day)) {
        return false;
    }

    $openingDays = [
        'friday', 'saturday', 'sunday'
    ];

    return in_array(strtolower($day), $openingDays, true);
}

避免嵌套得太深并尽早返回(第2部分)

坏:

function fibonacci(int $n)
{
    if ($n < 50) {
        if ($n !== 0) {
            if ($n !== 1) {
                return fibonacci($n - 1) + fibonacci($n - 2);
            } else {
                return 1;
            }
        } else {
            return 0;
        }
    } else {
        return 'Not supported';
    }
}

好:

function fibonacci(int $n): int
{
    if ($n === 0 || $n === 1) {
        return $n;
    }

    if ($n >= 50) {
        throw new \Exception('Not supported');
    }

    return fibonacci($n - 1) + fibonacci($n - 2);
}

少用无意义的变量名

别让读你的代码的人猜你写的变量是什么意思。 写清楚好过模糊不清
坏:

$l = ['Austin', 'New York', 'San Francisco'];

for ($i = 0; $i < count($l); $i++) {
    $li = $l[$i];
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
  // 等等, `$li` 又代表什么?
    dispatch($li);
}

好:

$locations = ['Austin', 'New York', 'San Francisco'];

foreach ($locations as $location) {
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    dispatch($location);
}

不要添加不必要上下文

如果从你的类名、对象名已经可以得知一些信息,就别再在变量名里重复。

坏:

class Car
{
    public $carMake;
    public $carModel;
    public $carColor;

    //...
}

好:

class Car
{
    public $make;
    public $model;
    public $color;

    //...
}

合理使用参数默认值,没必要在方法里再做默认值检测

不好:

不好,$breweryName 可能为 NULL.

function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void
{
    // ...
}

还行:

比上一个好理解一些,但最好能控制变量的值

function createMicrobrewery($name = null): void
{
    $breweryName = $name ?: 'Hipster Brew Co.';
    // ...
}

好:

如果你的程序只支持 PHP 7+, 那你可以用 type hinting 保证变量 $breweryName 不是 NULL.

function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void
{
    // ...
}

表达式

使用恒等式

不好:

简易对比会将字符串转为整形

$a = '42';
$b = 42;

if( $a != $b ) {
   //这里始终执行不到
}

对比 $a != $b 返回了 FALSE 但应该返回 TRUE ! 字符串 ‘42’ 跟整数 42 不相等

好:

使用恒等判断检查类型和数据

$a = '42';
$b = 42;

if ($a !== $b) {
    // The expression is verified
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
PHPer技术栈
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1

老生常谈的内容了

1周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!