Clean Code PHP 程式碼簡潔之道

PHPer技術棧發表於2021-01-13

介紹

來自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技術棧

相關文章