← Назад к вопросам

Расскажите о принципах SOLID. Приведите примеры применения в PHP.

2.0 Middle🔥 212 комментариев
#Архитектура и паттерны#ООП

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Принципы SOLID в PHP: подробное руководство с примерами

Введение в SOLID

SOLID — это акроним пяти фундаментальных принципов объектно-ориентированного программирования и проектирования, которые помогают создавать гибкий, поддерживаемый и масштабируемый код. Эти принципы были сформулированы Робертом Мартином и стали стандартом в разработке качественного ПО.

Принципы SOLID с примерами на PHP

1. Принцип единственной ответственности (Single Responsibility Principle)

Каждый класс должен иметь только одну причину для изменения, то есть выполнять лишь одну задачу.

Пример нарушения SRP:

class Order {
    private $items;
    private $customer;
    
    public function calculateTotal() {
        // логика расчета суммы
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item->price * $item->quantity;
        }
        return $total;
    }
    
    public function saveToDatabase() {
        // логика сохранения в БД
        // ...
    }
    
    public function sendEmailConfirmation() {
        // логика отправки email
        // ...
    }
}

Пример с соблюдением SRP:

class Order {
    private $items;
    private $customer;
    
    public function calculateTotal() {
        $total = 0;
        foreach ($this->items as $item) {
            $total += $item->price * $item->quantity;
        }
        return $total;
    }
    
    public function getItems() {
        return $this->items;
    }
    
    public function getCustomer() {
        return $this->customer;
    }
}

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

class EmailService {
    public function sendOrderConfirmation(Order $order) {
        // логика отправки email
        // ...
    }
}

2. Принцип открытости/закрытости (Open/Closed Principle)

Классы должны быть открыты для расширения, но закрыты для модификации.

Пример нарушения OCP:

class AreaCalculator {
    public function calculate($shape) {
        if ($shape instanceof Rectangle) {
            return $shape->width * $shape->height;
        } elseif ($shape instanceof Circle) {
            return pi() * pow($shape->radius, 2);
        }
        // При добавлении новой фигуры нужно изменять этот метод
    }
}

Пример с соблюдением OCP:

interface Shape {
    public function area();
}

class Rectangle implements Shape {
    private $width;
    private $height;
    
    public function __construct($width, $height) {
        $this->width = $width;
        $this->height = $height;
    }
    
    public function area() {
        return $this->width * $this->height;
    }
}

class Circle implements Shape {
    private $radius;
    
    public function __construct($radius) {
        $this->radius = $radius;
    }
    
    public function area() {
        return pi() * pow($this->radius, 2);
    }
}

class AreaCalculator {
    public function calculate(Shape $shape) {
        return $shape->area();
    }
}

// Теперь можно легко добавить новую фигуру без изменения AreaCalculator
class Triangle implements Shape {
    private $base;
    private $height;
    
    public function area() {
        return 0.5 * $this->base * $this->height;
    }
}

3. Принцип подстановки Барбары Лисков (Liskov Substitution Principle)

Объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы.

Пример нарушения LSP:

class Bird {
    public function fly() {
        return "I can fly";
    }
}

class Penguin extends Bird {
    public function fly() {
        throw new Exception("I cannot fly!");
    }
}

function makeBirdFly(Bird $bird) {
    return $bird->fly(); // Ошибка для пингвина!
}

Пример с соблюдением LSP:

abstract class Bird {
    abstract public function move();
}

class FlyingBird extends Bird {
    public function move() {
        return "I can fly";
    }
}

class NonFlyingBird extends Bird {
    public function move() {
        return "I can walk or swim";
    }
}

class Sparrow extends FlyingBird {
    // корректно наследует поведение
}

class Penguin extends NonFlyingBird {
    // корректно наследует поведение
}

function makeBirdMove(Bird $bird) {
    return $bird->move(); // Работает для всех птиц
}

4. Принцип разделения интерфейса (Interface Segregation Principle)

Клиенты не должны зависеть от методов, которые они не используют. Лучше иметь много специализированных интерфейсов, чем один общий.

Пример нарушения ISP:

interface Worker {
    public function work();
    public function eat();
    public function sleep();
}

class HumanWorker implements Worker {
    public function work() { /* ... */ }
    public function eat() { /* ... */ }
    public function sleep() { /* ... */ }
}

class RobotWorker implements Worker {
    public function work() { /* ... */ }
    public function eat() { /* ... */ } // Робот не ест!
    public function sleep() { /* ... */ } // Робот не спит!
}

Пример с соблюдением ISP:

interface Workable {
    public function work();
}

interface Eatable {
    public function eat();
}

interface Sleepable {
    public function sleep();
}

class HumanWorker implements Workable, Eatable, Sleepable {
    public function work() { /* ... */ }
    public function eat() { /* ... */ }
    public function sleep() { /* ... */ }
}

class RobotWorker implements Workable {
    public function work() { /* ... */ }
    // Не реализует ненужные методы
}

5. Принцип инверсии зависимостей (Dependency Inversion Principle)

Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций.

Пример нарушения DIP:

class MySQLDatabase {
    public function connect() {
        // подключение к MySQL
    }
    
    public function query($sql) {
        // выполнение запроса
    }
}

class UserRepository {
    private $database;
    
    public function __construct() {
        $this->database = new MySQLDatabase(); // Жесткая зависимость
    }
    
    public function getUsers() {
        $this->database->connect();
        return $this->database->query("SELECT * FROM users");
    }
}

Пример с соблюдением DIP:

interface DatabaseConnection {
    public function connect();
    public function query($sql);
}

class MySQLDatabase implements DatabaseConnection {
    public function connect() {
        // подключение к MySQL
    }
    
    public function query($sql) {
        // выполнение запроса
    }
}

class PostgreSQLDatabase implements DatabaseConnection {
    public function connect() {
        // подключение к PostgreSQL
    }
    
    public function query($sql) {
        // выполнение запроса
    }
}

class UserRepository {
    private $database;
    
    public function __construct(DatabaseConnection $database) {
        $this->database = $database; // Зависимость от абстракции
    }
    
    public function getUsers() {
        $this->database->connect();
        return $this->database->query("SELECT * FROM users");
    }
}

// Использование с внедрением зависимости
$mysqlDb = new MySQLDatabase();
$userRepository = new UserRepository($mysqlDb);

// Или с другой реализацией
$postgresDb = new PostgreSQLDatabase();
$userRepository = new UserRepository($postgresDb);

Преимущества применения SOLID

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

Практические рекомендации

  1. Начинайте с простых нарушений: В реальных проектах часто встречаются нарушения SRP — это хорошая точка для начала рефакторинга
  2. Используйте Dependency Injection: Это естественный способ соблюдать DIP в PHP
  3. Анализируйте перед рефакторингом: Не всегда нужно строго следовать всем принципам — оценивайте затраты и выгоды
  4. Комбинируйте с другими практиками: SOLID хорошо сочетается с паттернами проектирования, DDD и TDD

SOLID принципы — это не догма, а руководство к созданию качественного кода. В PHP они особенно актуальны благодаря широкой поддержке ООП и интерфейсов. Правильное применение этих принципов значительно повышает качество кодовой базы и упрощает долгосрочную поддержку проектов.