Что такое Clean Code и почему это важно в PHP?
Clean Code (чистый код) — это не просто модный термин, а философия разработки, которая помогает писать программы, понятные не только машине, но и человеку. В контексте PHP, где код часто поддерживается годами разными командами, следование принципам чистого кода становится критически важным навыком.
Чистый код обладает несколькими ключевыми характеристиками:
- Его легко читать и понимать без комментариев
- Он предсказуем и не вызывает "сюрпризов" при выполнении
- Его легко модифицировать без риска сломать другие части системы
- Он содержит минимум дублирования (принцип DRY)
В этой статье мы разберем основные принципы Clean Code на конкретных примерах PHP-кода.
1. Именование переменных и функций
Плохой пример: что не так с этим кодом?
// ❌ Плохой код
$a = 5;
$b = 10;
$c = $a * $b;
function calc($x, $y) {
return $x + $y * 0.2;
}
$d = calc($a, $b);
В этом примере совершенно непонятно, что означают переменные $a, $b, $c и что делает функция calc. Через месяц вы сами не вспомните, зачем писали этот код.
Хороший пример: осмысленные имена
// ✅ Хороший код
$productPrice = 5;
$quantity = 10;
$totalCost = $productPrice * $quantity;
function calculatePriceWithTax(float $basePrice, float $taxRate = 0.2): float {
return $basePrice + ($basePrice * $taxRate);
}
$finalPrice = calculatePriceWithTax($totalCost);
Правила именования в PHP:
- Используйте существительные для переменных (
$userName,$orderTotal) - Используйте глаголы для функций (
getUser(),calculateTotal()) - Не сокращайте имена (пишите
$customerAddress, а не$custAddr) - Избегайте однобуквенных переменных (кроме счетчиков циклов
$i,$j) - Булевы переменные начинайте с
is,has,can($isActive,$hasPermission)
2. Маленькие функции и принцип единой ответственности (SRP)
Проблема: функция-швейцарский нож
// ❌ Плохой код: функция делает всё сразу
function processOrder(array $orderData): array {
// Валидация
if (empty($orderData['email'])) {
throw new Exception('Email required');
}
// Сохранение в БД
$pdo = new PDO('mysql:host=localhost;dbname=shop', 'root', '');
$stmt = $pdo->prepare("INSERT INTO orders (email, total) VALUES (?, ?)");
$stmt->execute([$orderData['email'], $orderData['total']]);
// Отправка email
mail($orderData['email'], 'Order confirmed', 'Thank you!');
// Логирование
file_put_contents('log.txt', 'Order processed: ' . date('Y-m-d H:i:s') . PHP_EOL, FILE_APPEND);
return ['status' => 'success'];
}
Эта функция нарушает принцип единой ответственности (Single Responsibility Principle). Она занимается валидацией, работой с БД, отправкой почты и логированием. Любое изменение в одном из этих процессов потребует изменения всей функции.
Решение: декомпозиция на маленькие функции
// ✅ Хороший код: каждая функция отвечает за одно действие
function validateOrderData(array $orderData): void {
if (empty($orderData['email'])) {
throw new InvalidArgumentException('Email is required');
}
}
function saveOrderToDatabase(array $orderData): int {
$pdo = new PDO('mysql:host=localhost;dbname=shop', 'root', '');
$stmt = $pdo->prepare("INSERT INTO orders (email, total) VALUES (?, ?)");
$stmt->execute([$orderData['email'], $orderData['total']]);
return (int)$pdo->lastInsertId();
}
function sendOrderConfirmationEmail(string $email): void {
mail($email, 'Order confirmed', 'Thank you for your order!');
}
function logOrderProcessing(): void {
$logMessage = 'Order processed: ' . date('Y-m-d H:i:s') . PHP_EOL;
file_put_contents('log.txt', $logMessage, FILE_APPEND);
}
// Основная функция теперь просто координирует действия
function processOrder(array $orderData): array {
validateOrderData($orderData);
$orderId = saveOrderToDatabase($orderData);
sendOrderConfirmationEmail($orderData['email']);
logOrderProcessing();
return ['status' => 'success', 'order_id' => $orderId];
}
Преимущества маленьких функций:
- Их легко тестировать изолированно
- Код становится самодокументируемым
- Упрощается отладка — ошибка сразу локализуется в конкретной функции
- Функции можно переиспользовать в других местах
3. Избегаем дублирования кода (DRY) и магических чисел
Проблема: магические числа и повторяющийся код
// ❌ Плохой код: магические числа и дублирование
function calculateDiscount(float $price): float {
if ($price > 1000) {
return $price * 0.9; // 10% скидка
} elseif ($price > 500) {
return $price * 0.95; // 5% скидка
}
return $price;
}
function calculateBonus(float $salary): float {
if ($salary > 10000) {
return $salary * 0.9; // 10% бонус
} elseif ($salary > 5000) {
return $salary * 0.95; // 5% бонус
}
return $salary;
}
Здесь мы видим дублирование логики расчета процентов, а также "магические числа" 0.9, 0.95, 1000, 500, смысл которых неочевиден.
Решение: константы и общие функции
// ✅ Хороший код: константы и переиспользуемая логика
const HIGH_VALUE_THRESHOLD = 1000;
const