Принципы разработки программного обеспечения, из книги Роберта К. Мартина «Чистый код», адаптированной для PHP. Это не руководство по стилю. Это руководство по созданию читаемого, многоразового и рефакторируемого программного обеспечения на PHP.
Не каждый принцип должен строго соблюдаться, и еще меньше будет универсальными. Это руководящие принципы и не более того, но они кодифицированы многолетним коллективным опытом авторов Clean Code.
Хотя многие разработчики все еще используют PHP 5, большинство примеров в этой статье работают только с PHP 7.1+.
Используйте значащие и легко читаемые имена переменных
Плохо:
$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)
Плохо:
// Что означает 4 ?
if ($user->access & 4) {
// ...
}
Хорошо:
class User
{
const ACCESS_READ = 1;
const ACCESS_CREATE = 2;
const ACCESS_UPDATE = 4;
const ACCESS_DELETE = 8;
}
if ($user->access & User::ACCESS_UPDATE) {
// ...
}
Используйте поясняющие переменные
Плохо:
$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();
// ...
// ...
// ...
// Wait, what is `$li` for again?
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+, вы можете использовать подсказку типа и быть уверенным, что $ breweryName не будет NULL.
function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void
{
// ...
}