DSL in PHP: Domain-Specific Languages für Unternehmen erstellen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Was, wenn Code die Sprache deines Unternehmens sprechen würde?

\n\n

Stell dir vor: Ein Vertriebsmitarbeiter schreibt eine Rabattbedingung in verständlichem Deutsch, und das System wandelt sie automatisch in funktionierenden Code um. Oder ein Buchhalter beschreibt eine Steuerberechnung mit dem Satz: „Wenn der Betrag über 1000 liegt und der Kunde aus der EU kommt, wende 5 % an.“ Ohne eine einzige Zeile PHP. Klingt nach Science-Fiction? Willkommen in der Welt der Domain-Specific Languages (DSL) in PHP.

\n\n

Die meisten Entwickler kennen PHP als Sprache für das Web, aber nur wenige nutzen seine Superkraft – die Erstellung von DSL. Das ist kein reiner technischer Trick, sondern ein mächtiges Werkzeug, das Chaos aus Geschäftsregeln in eleganten, lesbaren Code verwandelt. In diesem Artikel sprechen wir nicht nur über Theorie, sondern bauen einen funktionierenden DSL in PHP von Grund auf. Du wirst sehen, wie die DSL-Entwicklung sowohl dir als auch deinen Kunden das Leben erleichtern kann.

\n\n

Was ist ein DSL und warum brauchst du es in PHP?

\n\n

Ein DSL (Domain Specific Language) ist eine Sprache, die auf eine bestimmte Aufgabe zugeschnitten ist. Im Gegensatz zu einer allgemeinen Programmiersprache (wie PHP, Java oder Python) spricht ein DSL die Sprache deiner Fachdomäne. Beispiele: SQL für Datenbanken, reguläre Ausdrücke für die Mustersuche, HTML für das Layout.

\n\n

Warum solltest du einen DSL in PHP erstellen? Drei Hauptgründe:

\n\n
    \n
  • Lesbarkeit. DSL-Code sieht aus wie eine Anleitung in Deutsch oder Englisch. Man muss kein Programmierer sein, um die Logik zu verstehen.
  • \n
  • Sicherheit. Du kontrollierst, was der Benutzer tun kann. Kein eval oder shell_exec.
  • \n
  • Entwicklungsgeschwindigkeit. Business-Analysten und Manager können Regeln selbst beschreiben, ohne das Entwicklungsteam zu belasten.
  • \n
\n\n

In PHP gibt es zwei Hauptansätze zur Erstellung von Domain-Specific Languages: interne DSL (basieren auf der PHP-Syntax) und externe DSL (erfordern einen eigenen Parser). Wir beginnen mit dem ersten – er ist einfacher und deckt oft 80 % der Aufgaben ab.

\n\n

Ansatz 1: Internes DSL – Fluent Interface und die Magie der Methoden

\n\n

Ein internes DSL nutzt die PHP-Syntax, organisiert sie aber so, dass sie an natürliche Sprache erinnert. Der Klassiker ist das Fluent Interface. Lass uns einen DSL für den Aufbau von SQL-Abfragen schreiben, um die Magie sofort zu erleben.

\n\n

Beispiel: DSL für SQL-Abfragen

\n\n

Anstatt zu schreiben:

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

Möchten wir so schreiben:

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

Das liest sich wie ein Satz, oder? Die Implementierung ist einfach: Jede Methode gibt $this zurück, und am Ende sammelt die Methode get() den String.

\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

Buchempfehlungen