PHP

Les design patterns PHP les plus utiles en 2026 (avec exemples)

Publié le 23 February 2026 — 3 min de lecture
En bref

Les design patterns PHP sont des solutions éprouvées à des problèmes récurrents de conception. Ce guide pratique vous présente les 8 patterns les plus utiles — Singleton, Repository, Factory, Observer — avec des exemples PHP 8 concrets.

Les design patterns sont des solutions réutilisables à des problèmes de conception logicielle récurrents. Les maîtriser transforme votre code PHP en quelque chose de maintenable, extensible et lisible par toute l’équipe. Voici les plus utiles avec des exemples PHP 8 directs.

1. Repository Pattern

Sépare la logique d’accès aux données de la logique métier. Le code qui utilise les données n’a pas besoin de savoir d’où elles viennent (MySQL, API, fichier) :

interface ArticleRepositoryInterface {
    public function findById(int $id): ?Article;
    public function findAll(): array;
    public function save(Article $article): void;
}

class MySQLArticleRepository implements ArticleRepositoryInterface {
    public function findById(int $id): ?Article {
        $row = $this->pdo->prepare('SELECT * FROM articles WHERE id = ?');
        $row->execute([$id]);
        return $row->fetch() ? Article::fromArray($row->fetch()) : null;
    }
    // ...
}

2. Factory Pattern

Crée des objets sans exposer la logique de création :

class NotificationFactory {
    public static function create(string $channel): NotificationInterface {
        return match($channel) {
            'email'  => new EmailNotification(),
            'sms'    => new SMSNotification(),
            'slack'  => new SlackNotification(),
            default  => throw new InvalidArgumentException("Channel inconnu: $channel"),
        };
    }
}
$notif = NotificationFactory::create('email');
$notif->send($message);

3. Observer Pattern

Permet à des objets de s’abonner à des événements d’autres objets. C’est la base des systèmes d’événements :

interface EventListener {
    public function handle(Event $event): void;
}

class EventDispatcher {
    private array $listeners = [];

    public function listen(string $event, EventListener $listener): void {
        $this->listeners[$event][] = $listener;
    }

    public function dispatch(Event $event): void {
        foreach ($this->listeners[$event::class] ?? [] as $listener) {
            $listener->handle($event);
        }
    }
}

// Usage
$dispatcher->listen(UserRegistered::class, new SendWelcomeEmail());
$dispatcher->listen(UserRegistered::class, new CreateUserProfile());
$dispatcher->dispatch(new UserRegistered($user));

4. Decorator Pattern

Ajoute des comportements à un objet sans modifier sa classe :

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

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

class TimestampLogger implements Logger {
    public function __construct(private Logger $inner) {}
    public function log(string $message): void {
        $this->inner->log('[' . date('c') . '] ' . $message);
    }
}

$logger = new TimestampLogger(new FileLogger());
$logger->log('Application démarrée'); // [2026-01-15T...] Application démarrée

5. Strategy Pattern

Encapsule des algorithmes interchangeables :

interface PricingStrategy {
    public function calculate(float $basePrice): float;
}
class StandardPricing implements PricingStrategy {
    public function calculate(float $basePrice): float { return $basePrice; }
}
class MemberPricing implements PricingStrategy {
    public function calculate(float $basePrice): float { return $basePrice * 0.85; }
}
class Cart {
    public function __construct(private PricingStrategy $pricing) {}
    public function total(float $price): float { return $this->pricing->calculate($price); }
}

6. Singleton (et pourquoi l’éviter)

Le Singleton garantit qu’une classe n’a qu’une seule instance. Souvent cité, mais à éviter en général car il crée un couplage global difficile à tester. Préférez l’injection de dépendances et laissez votre conteneur DI gérer les instances unique.

7. Command Pattern

Encapsule une action dans un objet — permet d’annuler, rejouer, logger les commandes :

interface Command { public function execute(): void; }
class PublishArticleCommand implements Command {
    public function __construct(private Article $article, private ArticleRepository $repo) {}
    public function execute(): void {
        $this->article->publish();
        $this->repo->save($this->article);
    }
}
$bus->dispatch(new PublishArticleCommand($article, $repo));

8. Value Object

Représente une valeur immuable avec sa propre logique de validation :

final class Email {
    private string $value;
    public function __construct(string $email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException("Email invalide: $email");
        }
        $this->value = strtolower($email);
    }
    public function __toString(): string { return $this->value; }
    public function equals(Email $other): bool { return $this->value === $other->value; }
}
$email = new Email('Alice@EXAMPLE.COM'); // alice@example.com — toujours valide

Les Value Objects éliminent les classes entières de bugs liés aux données invalides. C’est l’un des patterns DDD les plus accessibles et les plus rentables à adopter immédiatement.

W
Rédigé par
WebEngine
Développeur web freelance à Paris spécialisé WordPress, WooCommerce et SEO technique depuis 2010. 13 avis vérifiés · Note 5/5. Chaque site livré atteint un score PageSpeed mobile supérieur à 90.

Un projet en tête ?

Devis gratuit sous 48h, sans engagement.

Demander un devis gratuit