DSL en PHP : créez des langages dédiés pour votre métier

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Et si le code parlait le langage de votre entreprise ?

\n\n

Imaginez : un commercial rédige une condition de remise en anglais simple, et le système la transforme automatiquement en code fonctionnel. Ou un comptable décrit un calcul fiscal avec la phrase « Si le montant dépasse 1000 et que le client est dans l'UE, appliquer un taux de 5% ». Sans écrire une seule ligne de PHP. Utopique ? Bienvenue dans l'univers des langages dédiés (DSL) en PHP.

\n\n

La plupart des développeurs connaissent PHP comme langage web, mais peu exploitent sa superpuissance : la création de DSL. Ce n'est pas un simple tour technique, mais un outil puissant qui transforme le chaos des règles métier en code élégant et lisible. Dans cet article, nous ne nous contenterons pas de théorie : nous construirons ensemble un DSL en PHP fonctionnel, de zéro. Vous verrez comment le développement de DSL peut simplifier votre quotidien et celui de vos clients.

\n\n

Qu'est-ce qu'un DSL et pourquoi l'utiliser en PHP ?

\n\n

Un DSL (Domain Specific Language) est un langage conçu pour une tâche spécifique. Contrairement à un langage de programmation généraliste (comme PHP, Java ou Python), un DSL parle le langage de votre domaine métier. Exemples : SQL pour les bases de données, les expressions régulières pour la recherche de motifs, HTML pour le balisage.

\n\n

Pourquoi créer un DSL en PHP ? Trois raisons principales :

\n\n
    \n
  • Lisibilité. Le code DSL ressemble à une instruction en français. Pas besoin d'être programmeur pour comprendre la logique.
  • \n
  • Sécurité. Vous contrôlez ce que l'utilisateur peut faire. Fini les eval et shell_exec.
  • \n
  • Rapidité de développement. Les analystes métier et managers peuvent décrire eux-mêmes les règles, sans solliciter l'équipe technique.
  • \n
\n\n

En PHP, deux approches principales existent pour créer des langages dédiés : les DSL internes (basés sur la syntaxe PHP) et les DSL externes (nécessitant leur propre analyseur syntaxique). Nous commencerons par la première, plus simple et qui couvre 80% des besoins.

\n\n

Approche 1 : DSL interne — Fluent Interface et magie des méthodes

\n\n

Un DSL interne utilise la syntaxe PHP, mais organisée pour imiter le langage naturel. L'exemple classique est le fluent interface (interface fluide). Créons un DSL pour construire des requêtes SQL, afin de ressentir la magie immédiatement.

\n\n

Exemple : DSL pour construire des requêtes SQL

\n\n

Au lieu d'écrire :

\n\n
$query = "SELECT * FROM users WHERE age > 18 AND city = 'Paris' ORDER BY name ASC LIMIT 10";
\n\n

Nous voulons écrire :

\n\n
$query = QueryBuilder::table('users')\n    ->select('*')\n    ->where('age', '>', 18)\n    ->where('city', '=', 'Paris')\n    ->orderBy('name', 'ASC')\n    ->limit(10)\n    ->get();
\n\n

Avouez que cela se lit comme une phrase. L'implémentation est simple : chaque méthode retourne $this, et la méthode finale get() assemble la chaîne.

\n\n
class QueryBuilder {\n    private array $parts = [];\n\n    public function table(string $name): self {\n        $this->parts['table'] = $name;\n        return $this;\n    }\n\n    public function select(string $columns = '*'): self {\n        $this->parts['select'] = $columns;\n        return $this;\n    }\n\n    public function where(string $column, string $operator, $value): self {\n        $this->parts['where'][] = "$column $operator " . (is_string($value) ? "'$value'" : $value);\n        return $this;\n    }\n\n    public function orderBy(string $column, string $direction = 'ASC'): self {\n        $this->parts['order'] = "$column $direction";\n        return $this;\n    }\n\n    public function limit(int $limit): self {\n        $this->parts['limit'] = $limit;\n        return $this;\n    }\n\n    public function get(): string {\n        $sql = "SELECT {$this->parts['select']} FROM {$this->parts['table']}";\n        if (!empty($this->parts['where'])) {\n            $sql .= " WHERE " . implode(' AND                

Blogs

Book Recommendations