DSL em PHP: criando linguagens específicas para negócios

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

E se o código falasse a língua do seu negócio?

\n\n

Imagine: um gerente de vendas escreve uma regra de desconto em inglês simples, e o sistema a transforma automaticamente em código funcional. Ou um contador descreve um cálculo de imposto com a frase "Se o valor for maior que 1000 e o cliente for da UE, aplicar alíquota de 5%". Sem uma única linha de PHP. Parece ficção? Bem-vindo ao mundo das linguagens específicas de domínio (DSL) em PHP.

\n\n

A maioria dos desenvolvedores conhece o PHP como linguagem para web, mas poucos usam seu superpoder — a criação de DSL. Não é apenas um truque técnico, mas uma ferramenta poderosa que transforma o caos das regras de negócio em código elegante e legível. Neste artigo, não vamos apenas falar de teoria; vamos construir um DSL em PHP funcional do zero. Você verá como o desenvolvimento de DSL pode simplificar sua vida e a dos seus clientes.

\n\n

O que é DSL e por que você precisa dela em PHP?

\n\n

DSL (Domain Specific Language) é uma linguagem feita sob medida para uma tarefa específica. Diferente de uma linguagem de programação geral (como PHP, Java ou Python), a DSL fala a língua do seu domínio de negócio. Exemplos: SQL para bancos de dados, expressões regulares para busca de padrões, HTML para marcação.

\n\n

Por que criar uma DSL em PHP? Três razões principais:

\n\n
    \n
  • Legibilidade. O código em DSL parece uma instrução em português ou inglês. Não é preciso ser programador para entender a lógica.
  • \n
  • Segurança. Você controla o que o usuário pode fazer. Nada de eval ou shell_exec.
  • \n
  • Velocidade de desenvolvimento. Analistas de negócio e gerentes podem descrever regras por conta própria, sem sobrecarregar a equipe de desenvolvimento.
  • \n
\n\n

Em PHP, existem duas abordagens principais para criar linguagens específicas de domínio: DSLs internas (construídas sobre a sintaxe do PHP) e DSLs externas (que exigem um parser próprio). Vamos começar pela primeira — é mais simples e cobre 80% dos casos.

\n\n

Abordagem 1: DSL Interna — Fluent Interface e a mágica dos métodos

\n\n

Uma DSL interna é quando você usa a sintaxe do PHP, mas a organiza de forma que pareça uma linguagem natural. O clássico é o fluent interface (interface fluente). Vamos escrever uma DSL para construir consultas SQL e sentir a mágica agora mesmo.

\n\n

Exemplo: DSL para construir consultas SQL

\n\n

Em vez de escrever:

\n\n
$query = "SELECT * FROM usuarios WHERE idade > 18 AND cidade = 'São Paulo' ORDER BY nome ASC LIMIT 10";
\n\n

Queremos escrever assim:

\n\n
$query = QueryBuilder::table('usuarios')\n    ->select('*')\n    ->where('idade', '>', 18)\n    ->where('cidade', '=', 'São Paulo')\n    ->orderBy('nome', 'ASC')\n    ->limit(10)\n    ->get();
\n\n

Concorda que parece uma frase? A implementação é simples: cada método retorna $this, e no final o método get() monta a 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

Book Recommendations