14 августа 2025 г.
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;
}
}