Тест на вакансию

SOLID принципы на примерах PHP

14 августа 2025 г.
69
SOLID это набор принципов объектно-ориентированного программирования, которые помогают создавать поддерживаемый и масштабируемый код. Рассмотрим каждый принцип с примерами на PHP.

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

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

Плохой пример:
class Report {
    public function getTitle() {
        return "Report Title";
    }
   
    public function getDate() {
        return "2023-05-01";
    }
   
    public function getContents() {
        return [
            'title' => $this->getTitle(),
            'date' => $this->getDate()
        ];
    }
   
    public function formatJson() {
        return json_encode($this->getContents());
    }
}
Хороший пример:
class Report {
    public function getTitle() {
        return "Report Title";
    }
   
    public function getDate() {
        return "2023-05-01";
    }
   
    public function getContents() {
        return [
            'title' => $this->getTitle(),
            'date' => $this->getDate()
        ];
    }
}
class JsonReportFormatter {
    public function format(Report $report) {
        return json_encode($report->getContents());
    }
}

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

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

Плохой пример:
class Circle {
    public $radius;
}
class Square {
    public $length;
}
class AreaCalculator {
    public function calculate($shape) {
        if ($shape instanceof Circle) {
            return pi() * $shape->radius ** 2;
        } elseif ($shape instanceof Square) {
            return $shape->length ** 2;
        }
       
        throw new Exception("Unsupported shape");
    }
}
Хороший пример:
interface Shape {
    public function area();
}
class Circle implements Shape {
    private $radius;
   
    public function __construct($radius) {
        $this->radius = $radius;
    }
   
    public function area() {
        return pi() * $this->radius ** 2;
    }
}
class Square implements Shape {
    private $length;
   
    public function __construct($length) {
        $this->length = $length;
    }
   
    public function area() {
        return $this->length ** 2;
    }
}
class AreaCalculator {
    public function calculate(Shape $shape) {
        return $shape->area();
    }
}

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

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

Плохой пример:
class Rectangle {
    protected $width;
    protected $height;
   
    public function setWidth($width) {
        $this->width = $width;
    }
   
    public function setHeight($height) {
        $this->height = $height;
    }
   
    public function area() {
        return $this->width * $this->height;
    }
}
class Square extends Rectangle {
    public function setWidth($width) {
        $this->width = $width;
        $this->height = $width;
    }
   
    public function setHeight($height) {
        $this->height = $height;
        $this->width = $height;
    }
}
function testRectangle(Rectangle $rectangle) {
    $rectangle->setWidth(4);
    $rectangle->setHeight(5);
    return $rectangle->area(); // Ожидается 20, но для Square вернет 25
}
Хороший пример:
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 Square implements Shape {
    private $length;
   
    public function __construct($length) {
        $this->length = $length;
    }
   
    public function area() {
        return $this->length ** 2;
    }
}
function testShape(Shape $shape) {
    return $shape->area();
}

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

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

Плохой пример:
interface Worker {
    public function work();
    public function eat();
}
class HumanWorker implements Worker {
    public function work() {
        echo "Human working\n";
    }
   
    public function eat() {
        echo "Human eating\n";
    }
}
class RobotWorker implements Worker {
    public function work() {
        echo "Robot working\n";
    }
   
    public function eat() {
        // Роботы не едят, но вынуждены реализовывать этот метод
        throw new Exception("Robots don't eat");
    }
}
Хороший пример:
interface Workable {
    public function work();
}
interface Eatable {
    public function eat();
}
class HumanWorker implements Workable, Eatable {
    public function work() {
        echo "Human working\n";
    }
   
    public function eat() {
        echo "Human eating\n";
    }
}
class RobotWorker implements Workable {
    public function work() {
        echo "Robot working\n";
    }
}

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

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

Плохой пример:
class MySQLConnection {
    public function connect() {
        // Логика подключения к MySQL
        return "MySQL connection";
    }
}
class PasswordReminder {
    private $dbConnection;
   
    public function __construct(MySQLConnection $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
Хороший пример:
interface DBConnectionInterface {
    public function connect();
}

class MySQLConnection implements DBConnectionInterface {
    public function connect() {
        // Логика подключения к MySQL
        return "MySQL connection";
    }
}

class PostgreSQLConnection implements DBConnectionInterface {
    public function connect() {
        // Логика подключения к PostgreSQL
        return "PostgreSQL connection";
    }
}

class PasswordReminder {
    private $dbConnection;
    
    public function __construct(DBConnectionInterface $dbConnection) {
        $this->dbConnection = $dbConnection;
    }
}
Поделиться: