9

我有个主意。我想通过编写一些简单的代码,让我们的客户能够根据许多变量指定定价:

if customer.zip is "37208"
   return 39.99
else
   return 59.99

在我的代码中,我会做这样的事情:

try {
   $variables = array('customer' => array('zip' => '63901'));
   $code = DSL::parse(DSL::tokenize($userCode))
   $returnValue = DSL::run($code, $variables);
} catch (SyntaxErrorException $e) {
   ...
}

我想我想要的是在 PHP 中创建一个简单的 DSL,它允许我们的客户在设置定价方面有很大的灵活性,而不必让我们对每个案例都进行编码。

这是基本思想:

  1. 我会提供一组变量和客户编写的代码。
  2. 解析器将评估用户使用提供的变量编写的代码,并将客户返回的值返回给我。它会为任何语法错误等引发异常。
  3. 然后我会在应用程序的正常逻辑中使用返回的值。

那么你知道在 PHP 中构建简单 DSL 的任何资源或框架吗?任何想法从哪里开始?

谢谢!

4

3 回答 3

10

抛开技术限制不谈,你可能真的要三思而后行,将这种编程能力赋予(我认为)非程序员。他们可能会以完全不可预测的方式搞砸,而您将成为必须清理混乱的人。至少要通过大量测试来保护它。也可能是法律术语。

但是你问了一个问题,所以我会试着回答这个问题。内部风格的 DSL(大多数人使用 DSL 一词时的意思)和外部风格的 DSL(更像是一种迷你语言)之间存在区别。Ruby 以拥有适合内部风格 DSL 的语法而闻名。另一方面,PHP 在这方面相当糟糕。

也就是说,您仍然可以在 PHP 中做一些事情——最简单的可能就是编写一个函数库,然后让您的客户使用该库以纯 PHP 编写代码。当然,您必须审核代码,但它会提供使用现有运行时的所有好处。

如果这还不够花哨,您将不得不深入研究沉重的东西。首先你需要一个解析器。如果你知道如何,它们可以很容易地手写,但除非你在学校被迫写一个,或者你有一个奇怪的爱好,只是为了好玩而写那种东西(我愿意),它可能会带你一个一点工作。解析器的基本组件是标记器和某种自动机(状态机),它将标记排列成树形结构(AST)。

一旦你有你的解析结构,你需要评估它。由于这是一个 DSL,特性的数量是有限的,性能可能不是你最关心的问题,你可以围绕 AST 编写一些面向对象的代码,然后就这样。否则,您可以选择编写某种解释器或将其交叉编译成另一种格式(PHP 将是一个明显的选择)。

整个过程中最棘手的部分主要是处理边缘情况,例如语法错误并向用户报告有意义的内容。再说一次,只要给 PHP 的一个子集的访问权限,就可以免费为您提供,所以请先考虑这一点。

于 2012-12-18T20:30:45.297 回答
3

如果其他人正在寻找另一种选择 - 考虑使用 Twig 创建集成到 Pico CMS ( http://pico.dev7studios.com/# )的 DSL/解析 ( http://twig.sensiolabs.org/ ) .

于 2014-02-19T21:43:18.597 回答
2

构建 DSL 解析器的标准方法是使用解析器生成器,也就是编译器-编译器来完成繁重的工作。这允许开发人员以抽象的BNF式语法表达 DSL,而不必深入解析和词法分析的本质。

示例包括C 中的Yacc、Perl 中的Regexp::Grammars和针对 Java 和其他几种语言的ANTLR等。PHP 选项似乎是PHP-PEG

于 2015-01-08T22:01:53.157 回答