Что такое принцип открытости/закрытости (OCP)?

«Что такое принцип открытости/закрытости (OCP)?» — вопрос из категории ООП, который задают на 31% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Принцип открытости/закрытости (Open/Closed Principle, OCP) — один из принципов SOLID. Он гласит: программные сущности (классы, модули, функции) должны быть открыты для расширения, но закрыты для модификации.

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

Практический пример из моей работы: В проекте была система отчетов, которая изначально генерировала только PDF. Когда понадобилось добавить экспорт в Excel и CSV, вместо того чтобы модифицировать класс ReportGenerator, я выделил абстракцию.

// Абстракция, закрытая для модификации
interface ReportExporter {
    public function export(array $data): string;
}

// Конкретные реализации, открытые для расширения
class PdfReportExporter implements ReportExporter {
    public function export(array $data): string {
        // Логика генерации PDF
        return "PDF content";
    }
}

class ExcelReportExporter implements ReportExporter {
    public function export(array $data): string {
        // Логика генерации Excel (использую библиотеку PhpSpreadsheet)
        return "Excel file";
    }
}

// Класс, который использует экспортер. Его код не меняется при добавлении новых форматов.
class ReportGenerator {
    public function __construct(private ReportExporter $exporter) {}

    public function generate(array $data): string {
        // ... подготовка данных ...
        return $this->exporter->export($data);
    }
}

// Использование
$pdfGenerator = new ReportGenerator(new PdfReportExporter());
$excelGenerator = new ReportGenerator(new ExcelReportExporter());

Итог: Чтобы добавить экспорт в CSV, мне нужно было лишь создать новый класс CsvReportExporter, реализующий интерфейс ReportExporter. Класс ReportGenerator остался нетронутым, что свело к нулю риск сломать существующую функциональность.