介紹
來自Robert C. Martin的書Clean Code的軟體工程原理, 適用於PHP。這不是樣式指南。這是在PHP中生產可讀,可重用和可重構軟體的指南。
並非必須嚴格遵循本文中的每個原則,而且將被普遍接受的原則甚至更少。這些只是準則,僅此而已,但它們是由Clean Code的作者在多年的集體經驗中整理而成的。
儘管許多開發人員仍然使用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 協議》,轉載必須註明作者和本文連結