Что означает буква L (Liskov Substitution Principle) в SOLID?

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

Ответ

L — Принцип подстановки Лисков (Liskov Substitution Principle, LSP).

Формулировка: Объекты базового класса должны быть заменяемы объектами его подклассов без изменения корректности программы. Наследник не должен ужесточать предусловия или ослаблять постусловия, определённые базовым классом.

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

interface Document {
    public function open(): string;
    public function save(): void;
}

class ReadOnlyDocument implements Document {
    public function open(): string {
        return 'Document content';
    }
    public function save(): void {
        // Нарушение LSP! Подкласс не может выполнить контракт базового класса.
        throw new RuntimeException('Save is not allowed for read-only documents');
    }
}

function processDocument(Document $doc) {
    $content = $doc->open();
    // Для ReadOnlyDocument вызовет неожиданное исключение
    $doc->save();
}

Исправление через пересмотр иерархии:

interface Document {
    public function open(): string;
}

interface WritableDocument extends Document {
    public function save(): void;
}

class PdfDocument implements WritableDocument {
    public function open(): string { /* ... */ }
    public function save(): void { /* ... */ }
}

class ReadOnlyReport implements Document {
    public function open(): string { /* ... */ }
    // Не реализует save(), что корректно
}

function processDocument(Document $doc) {
    $content = $doc->open();
    // Теперь функция работает с любым Document
}

function saveDocument(WritableDocument $doc) {
    $doc->save(); // Гарантировано безопасно
}

На практике LSP обеспечивает: предсказуемость полиморфного поведения, упрощение модульного тестирования (можно использовать моки базового типа) и предотвращение появления в коде проверок типа if ($obj instanceof SpecificClass).