Паттерны проектирования в PHP с примерами: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Паттерны проектирования в PHP: от основ до продвинутых техник

Паттерны проектирования (design patterns) — это многократно проверенные решения типовых задач, возникающих при разработке программного обеспечения. Для PHP-разработчика знание паттернов — это не просто галочка в резюме, а реальный инструмент для создания гибкого, поддерживаемого и масштабируемого кода. В этой статье мы разберем три ключевые группы паттернов GoF (банды четырех) с конкретными примерами на PHP, которые вы сможете сразу применить в своих проектах.

1. Порождающие паттерны (Creational Patterns)

Эти паттерны отвечают за создание объектов, скрывая логику инстанцирования и делая систему независимой от способа создания и композиции объектов.

Singleton (Одиночка)

Гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему. Классический пример — подключение к базе данных.

<?php
class Database {
    private static ?Database $instance = null;
    private PDO $pdo;

    private function __construct() {
        $this->pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
    }

    public static function getInstance(): Database {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function query(string $sql): array {
        // Логика выполнения запроса
        return $this->pdo->query($sql)->fetchAll();
    }

    // Запрещаем клонирование и десериализацию
    private function __clone() {}
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }
}

// Использование
$db = Database::getInstance();
$results = $db->query("SELECT * FROM users");
?>

Factory Method (Фабричный метод)

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

<?php
interface Logger {
    public function log(string $message): void;
}

class FileLogger implements Logger {
    public function log(string $message): void {
        file_put_contents('app.log', $message . PHP_EOL, FILE_APPEND);
    }
}

class DatabaseLogger implements Logger {
    public function log(string $message): void {
        // Сохраняем в БД
        echo "Logged to DB: $message\n";
    }
}

abstract class LoggerFactory {
    abstract public function createLogger(): Logger;

    public function logMessage(string $message): void {
        $logger = $this->createLogger();
        $logger->log($message);
    }
}

class FileLoggerFactory extends LoggerFactory {
    public function createLogger(): Logger {
        return new FileLogger();
    }
}

class DatabaseLoggerFactory extends LoggerFactory {
    public function createLogger(): Logger {
        return new DatabaseLogger();
    }
}

// Использование
$factory = new FileLoggerFactory();
$factory->logMessage("Это сообщение будет записано в файл");
?>

2. Структурные паттерны (Structural Patterns)

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

Adapter (Адаптер)

Позволяет объектам с несовместимыми интерфейсами работать вместе. Адаптер выступает в роли обертки, преобразующей вызовы одного интерфейса в другой.

<?php
// Старый класс с неудобным интерфейсом
class OldPaymentSystem {
    public function processPayment(float $amount, string $currency): string {
        return "Processing $amount $currency via legacy system";
    }
}

// Новый интерфейс, который мы хотим использовать
interface NewPaymentInterface {
    public function pay(float $amount): string;
}

// Адаптер
class PaymentAdapter implements NewPaymentInterface {
    private OldPaymentSystem $oldSystem;

    public function __construct(OldPaymentSystem $oldSystem) {
        $this->oldSystem = $oldSystem;
    }

    public function pay(float $amount): string {
        // Преобразуем вызов: новый интерфейс → старый метод
        return $this->oldSystem->processPayment($amount, 'USD');
    }
}

// Использование
$oldSystem = new OldPaymentSystem();
$adapter = new PaymentAdapter($oldSystem);
echo $adapter->pay(100.50); // Processing 100.5 USD via legacy system
?>

Decorator (Декоратор)

Динамически добавляет объекту новые обязанности, не изменяя его структуру. Является альтернативой наследованию.

<?php
interface Coffee {
    public function cost(): float;
    public function description(): string;
}

class SimpleCoffee implements Coffee {
    public function cost(): float {
        return 10.0;
    }

    public function description(): string {
        return "Simple coffee";
    }
}

abstract class CoffeeDecorator implements Coffee {
    protected Coffee $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }
}

class MilkDecorator extends CoffeeDecorator {
    public function cost(): float {
        return $this->coffee->cost() + 2.0;
    }

    public function description(): string {
        return $this->coffee->description() . ", with milk";
    }
}

class SugarDecorator extends CoffeeDecorator {
    public function cost(): float {
        return $this->coffee->cost() + 0.5;
    }

    public function description(): string {
        return $this->coffee->description() . ", with sugar";
    }
}

// Использование
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);
echo $coffee->description() . " costs: " . $coffee->cost(); 
// Simple coffee, with milk, with sugar costs: 12.5
?>

3. Поведенческие паттерны (Behavioral Patterns)

Определяют алгоритмы и способы взаимодействия между объектами, распределяя обязанности между ними.

Strategy (Стратегия)

Определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Позволяет изменять алгоритм независимо от клиентов, которые его используют.

<?php
interface SortStrategy {
    public function sort(array $data): array;
}

class BubbleSortStrategy implements SortStrategy {
    public function sort(array $data): array {
        echo "Using Bubble Sort\n";
        // Реализация пузырьковой сортировки
        $n = count($data);
        for ($i = 0; $i < $n - 1; $i++) {
            for ($j = 0; $j < $n - $i - 1; $j++) {
                if ($data[$j] > $data[$j + 1]) {
                    $temp = $data[$j];
                    $                

Блоги

Рекомендаций по книгам