DSL在PHP中:为业务编写领域特定语言

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

如果代码能说您业务的语言会怎样?

\n\n

想象一下:销售经理用他理解的英语编写折扣条件,系统自动将其转化为可工作的代码。或者会计师用一句话描述税务计算:“如果金额大于1000且客户来自欧盟,则应用5%的税率”。无需一行PHP代码。听起来像科幻?欢迎来到PHP中的领域特定语言(DSL)世界。

\n\n

大多数开发者知道PHP是一种用于Web的语言,但很少有人使用它的超能力——创建DSL。这不仅仅是一个技术技巧,而是一个强大的工具,能将混乱的业务规则转化为优雅、可读的代码。在本文中,我们不仅会讨论理论,还会从头开始构建一个可工作的PHP DSL。您将看到DSL开发如何简化您和客户的生活。

\n\n

什么是DSL,为什么在PHP中需要它?

\n\n

DSL(领域特定语言)是一种针对特定任务量身定制的语言。与通用编程语言(如PHP、Java或Python)不同,DSL使用您领域内的语言。示例:用于数据库的SQL、用于模式搜索的正则表达式、用于布局的HTML。

\n\n

为什么要在PHP中创建DSL?三个主要原因:

\n\n
    \n
  • 可读性。DSL代码看起来像俄语或英语的指令。无需成为程序员就能理解逻辑。
  • \n
  • 安全性。您可以控制用户能做什么。没有eval和shell_exec。
  • \n
  • 开发速度。业务分析师和经理可以自己描述规则,无需打扰开发团队。
  • \n
\n\n

在PHP中,有两种主要方法用于创建领域特定语言:内部DSL(基于PHP语法构建)和外部DSL(需要自己的解析器)。我们从第一种开始——它更简单,通常能覆盖80%的任务。

\n\n

方法1:内部DSL——流畅接口和方法的魔力

\n\n

内部DSL是指您使用PHP语法,但将其组织得类似于自然语言。经典方法是流畅接口。让我们编写一个用于构建SQL查询的DSL,以便立即感受这种魔力。

\n\n

示例:用于构建SQL查询的DSL

\n\n

与其编写:

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

我们想这样写:

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

您同意,读起来像一个句子。实现很简单:每个方法返回$this,最后get()方法组装字符串。

\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                

博客

书籍推荐