用PHP实现DSL

时间:2012-12-18 20:05:44

标签: php dsl

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

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. 然后我会在应用程序的正常逻辑中使用返回的值。
  4. 您是否了解在PHP中构建简单DSL的任何资源或框架?任何想法从哪里开始?

    谢谢!

3 个答案:

答案 0 :(得分:7)

除了技术限制之外,你可能想要真正三思而后行(非假设)非程序员。他们可能会以完全不可预测的方式陷入困境,你将成为必须清理混乱的人。至少要通过大量测试来保护它。也可能是法律术语。

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

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

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

获得解析后的结构后,需要对其进行评估。由于这是一个DSL,功能的数量是有限的,性能可能不是你最关心的问题,你可以在AST周围编写一些面向对象的代码并保留它。否则,您可以选择编写某种解释器或将其交叉编译为另一种格式(PHP将是一个明显的选择)。

通过这个棘手的部分主要是处理边缘情况,例如语法错误,并向用户报告有意义的内容。再一次,只是给予访问PHP的一个子集,将免费提供给你,所以首先考虑一下。

答案 1 :(得分:3)

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

答案 2 :(得分:1)

构建DSL解析器的标准方法是使用解析器生成器(即compiler-compiler)来完成繁重的工作。这允许开发人员以抽象的BNF - ish语法表达DSL,而不必深入了解解析和lexing的细节。

示例包括C中的Yacc,Perl中的Regexp::GrammarsANTLR,其中包含Java和其他几种语言等.PHP选项似乎是PHP-PEG