Clean Code на PHP: принципы и примеры для чистого кода

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clean Code на PHP: принципы и примеры на практике

Чистый код — это не роскошь, а необходимость для любого профессионального PHP-разработчика. Когда вы пишете код, который легко читать, понимать и изменять, вы экономите время себе и своей команде. В этой статье мы разберем ключевые принципы Clean Code на PHP с конкретными примерами, которые можно сразу применить в проектах.

Почему чистый код важен для PHP-проектов?

PHP — гибкий язык, но эта гибкость часто приводит к хаосу, если не следить за качеством кода. Чистый код помогает:

  • Быстрее находить и исправлять ошибки;
  • Легко добавлять новые функции без риска сломать существующую логику;
  • Сокращать время вхождения в проект для новых разработчиков;
  • Повышать общую стабильность приложения.

Давайте перейдем к конкретным принципам и примерам.

Правильные имена переменных и функций

Первый шаг к чистому коду — осмысленные имена. Имя должно отвечать на вопрос "Что это?" или "Что делает?".

Плохой пример

<?php
$a = 86400;
$b = $a * 7;
$c = $b * 0.8;

Хороший пример (Clean Code)

<?php
$secondsPerDay = 86400;
$weeklySeconds = $secondsPerDay * 7;
$discountedWeeklySeconds = $weeklySeconds * 0.8;

Принцип: Имена должны быть описательными и не требовать комментариев. Избегайте сокращений (кроме общепринятых, например $i для счетчика цикла).

Пример для функций

<?php
// Плохо
function calc($a, $b) {
    return $a + $b * 1.2;
}

// Хорошо
function calculateTotalWithTax(float $price, float $taxRate = 0.2): float {
    return $price * (1 + $taxRate);
}

Принцип единой ответственности (SRP) в классах

Один из принципов SOLID гласит: "У класса должна быть только одна причина для изменения". Это значит, что каждый класс должен отвечать за одну конкретную задачу.

Нарушение SRP

<?php
class OrderProcessor {
    public function process(Order $order) {
        // Валидация заказа
        if (empty($order->items)) {
            throw new Exception("Пустой заказ");
        }
        
        // Сохранение в БД
        $this->saveToDatabase($order);
        
        // Отправка email
        mail($order->email, "Заказ оформлен", "Спасибо за покупку!");
        
        // Генерация PDF счета
        $this->generateInvoice($order);
    }
}

Чистая реализация с SRP

<?php
class OrderValidator {
    public function validate(Order $order): void {
        if (empty($order->items)) {
            throw new Exception("Пустой заказ");
        }
    }
}

class OrderRepository {
    public function save(Order $order): void {
        // Логика сохранения в БД
    }
}

class EmailNotifier {
    public function sendOrderConfirmation(Order $order): void {
        mail($order->email, "Заказ оформлен", "Спасибо за покупку!");
    }
}

class InvoiceGenerator {
    public function generate(Order $order): string {
        // Генерация PDF
        return "invoice_".$order->id.".pdf";
    }
}

// Использование
class OrderProcessor {
    public function __construct(
        private OrderValidator $validator,
        private OrderRepository $repository,
        private EmailNotifier $notifier,
        private InvoiceGenerator $invoiceGenerator
    ) {}
    
    public function process(Order $order): void {
        $this->validator->validate($order);
        $this->repository->save($order);
        $this->notifier->sendOrderConfirmation($order);
        $this->invoiceGenerator->generate($order);
    }
}

Теперь каждый класс отвечает за свою зону ответственности, что упрощает тестирование и поддержку.

Избегание "магических чисел" и дублирования

Магические числа — это числовые литералы, значение которых непонятно без контекста. Они делают код хрупким и сложным для изменения.

Плохой код

<?php
function getDiscount($price) {
    if ($price > 1000) {
        return $price * 0.9; // 10% скидка
    } elseif ($price > 500) {
        return $price * 0.95; // 5% скидка
    }
    return $price;
}

Чистый код с константами

<?php
class DiscountCalculator {
    const HIGH_VALUE_THRESHOLD = 1000;
    const MEDIUM_VALUE_THRESHOLD = 500;
    const HIGH_DISCOUNT_RATE = 0.9;
    const MEDIUM_DISCOUNT_RATE = 0.95;
    
    public function applyDiscount(float $price): float {
        if ($price > self::HIGH_VALUE_THRESHOLD) {
            return $price * self::HIGH_DISCOUNT_RATE;
        }
        
        if ($price > self::MEDIUM_VALUE_THRESHOLD) {
            return $price * self::MEDIUM_DISCOUNT_RATE;
        }
        
        return $price;
    }
}

Совет: Выносите повторяющиеся значения в константы или конфигурационные файлы. Это делает код самодокументируемым.

Управление условиями и ранний возврат (Early Return)

Глубоко вложенные if — признак плохого кода. Используйте ранний возврат для упрощения логики.

Плохо

<?php
function processUser($user) {
    if ($user) {
        if ($user->isActive()) {
            if ($user->hasPermission('admin')) {
                // Сложная логика
                return "Admin access granted";
            } else {
                return "No permission";
            }
        } else {
            return "User not active";
        }
    } else {
        return "User not found";
    }
}

Хорошо (Clean Code)

<?php
function processUser($user): string {
    if (!$user) {
        return "User not found";
    }
    
    if (!$user->isActive()) {
        return "User not active";
    }
    
    if (!$user->hasPermission('admin')) {
        return "No permission";
    }
    
    return "Admin access granted";
}

Такой код читается как последовательность проверок сверху вниз, что гораздо понятнее.

Блоги

Рекомендаций по книгам