如果代码能说您业务的语言会怎样?
\n\n想象一下:销售经理用他理解的英语编写折扣条件,系统自动将其转化为可工作的代码。或者会计师用一句话描述税务计算:“如果金额大于1000且客户来自欧盟,则应用5%的税率”。无需一行PHP代码。听起来像科幻?欢迎来到PHP中的领域特定语言(DSL)世界。
\n\n大多数开发者知道PHP是一种用于Web的语言,但很少有人使用它的超能力——创建DSL。这不仅仅是一个技术技巧,而是一个强大的工具,能将混乱的业务规则转化为优雅、可读的代码。在本文中,我们不仅会讨论理论,还会从头开始构建一个可工作的PHP DSL。您将看到DSL开发如何简化您和客户的生活。
\n\n什么是DSL,为什么在PHP中需要它?
\n\nDSL(领域特定语言)是一种针对特定任务量身定制的语言。与通用编程语言(如PHP、Java或Python)不同,DSL使用您领域内的语言。示例:用于数据库的SQL、用于模式搜索的正则表达式、用于布局的HTML。
\n\n为什么要在PHP中创建DSL?三个主要原因:
\n\n- \n
- 可读性。DSL代码看起来像俄语或英语的指令。无需成为程序员就能理解逻辑。 \n
- 安全性。您可以控制用户能做什么。没有eval和shell_exec。 \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\nclass 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