是否可以使用字符串变量作为if块中的整个条件(不使用eval())?

时间:2014-01-10 20:57:27

标签: php

作为背景,我正在编写解析csv文件的PHP代码,并对每个csv文件的每一行执行某些操作。那是什么"东西"取决于行中的值。使用" if"来测试值很容易。但是,由于两个原因,硬编码条件不是最佳的:

  1. 有几百个可能的测试条件。这只是为了开始。将来会增加更多条件。

  2. 每个csv行不需要针对每个条件进行测试;只要行的条件评估为真,就不需要评估其他条件。

  3. 理想情况下,对于我的情况," if"条件将存储在postgres表中,逐个放入字符串变量,然后每个变量将由单个if结构(在某种循环内)测试,直到条件计算为true。

    简化示例:

    $arrayOne[3] = "foo";
    
    // in practice, the value of this variable would not be hard-coded;
    // it would come from a postgres table
    $conditionString="\$arrayOne[3] == \"VANILLA\"";
    
    if($conditionString) {
        // do something, then exit the loop this if statement would be
        // inside of in actual practice
    }
    

    这个问题基本上是在

    提出的

    PHP - if condition inside string

    有三个基本答案:

    1. 您可以使用eval(),但不要使用!这是邪恶的! (同意)
    2. 对所有条件进行硬编码(由于上述原因和其他原因而不是最佳的)
    3. 将条件存储在架构中(这就是我正在做的事情),然后解析并转换为php代码。
    4. 解决方案3通常是我正在寻找的,但第二部分似乎效率低下且不必要地复杂。毕竟,为什么只需要存储然后评估你需要的单个字符串就更容易从多个字符串(顺便说一下,这会使postgres中的存储变得复杂)中构建php代码?

      有办法吗?

      非常感谢到目前为止的回复。 ComFreek,特别感谢您的详细回复。你建议的解决方案可能正是我所需要的,但坦率地说,如果情况确实如此,我没有经验可以立即知道。我肯定会花时间去理解你所说的话。希望它能解决我的问题。

      如果它没有,在此期间,回答其他人提出的几个问题:

      1)if条件通常不会很简单。许多将包含多个复合AND和OR测试。伪代码中的样本条件可能是:(field2 ==" BUY" AND(strpos(" REINVEST DIVIDEND",field6)或strpos(" CASH MERGER, field6))AND field2!=" TTXY" AND field3> 0)。

      2)CSV文件来自众多金融机构。它们包含大致相同的信息,但每个都有唯一的数据,并且所有数据都包含在不同位置的数据。他们还以不同的方式表达数据。在某些情况下,付款用负数表示;在其他人中,以正数表示。有些人有单独的存款和取款领域;一些表示存款和取款,另一栏中有代码。等等。代码需要确定交易的性质(信用卡购买,支票,股票买卖,退休金,等等)然后,如果可以的话,分配正确的借方/贷方账号(从图表中帐户)到该交易。总而言之,有数百种可能的条件,可能成千上万。 (如果有人想知道,代码可以确定特定csv文件来自的机构,并将仅针对与该机构相关的条件测试该文件中的交易。)

      3)代码需要足够灵活,以便轻松(换句话说,无需编写新代码)允许将来添加新测试。对我来说,能够为postgres表添加一个新条件(这将是要检查的代码的另一个测试)是足够的灵活性。

      尝试回答Phil的问题和评论(我可能无法正确理解):

      1)我知道preg_match是什么,但是还没有真正探索它能做什么,所以它实际上可能是我的问题的答案。我会检查一下。

      2)目前,代码不对事务进行分组(也就是说来自单个csv文件的单行);相反,它查看每一行,确定它是什么,然后在适当的postgres表中存储一个额外的数据,然后移动到下一行。有某些"类型"交易(比如信用卡购买)但它们从未被分组以进行进一步处理。

      3)每个交易应该满足唯一条件(尽管这个条件可能很复杂)。

      4)关于匹配整个字符串,除非我遗漏了某些东西(非常可能),但事情并非如此简单。例如,假设某个交易是股票购买。代码可以通过查看" action"来确定字段包含单词" Buy"和#34;数量"字段大于零(这些条件中的一个或另一个可能不足以确定交易是股票购买),但"自动收报机"字段可以是预先不知道的数千个字符串中的任何字符串 - " GOOG"," MSFT"," KO"或者其他什么。

      再次感谢所有回复到目前为止。

1 个答案:

答案 0 :(得分:6)

摘要:为特定的比较类型构建可扩展的处理程序系统,并将相关数据存储在数据库中。

您需要

  • 众所周知的各种条件
  • 可注册处理程序的可扩展系统,用于处理特定类型的条件 (例如EqualityHandlerStringLengthComparisionHandler
  • 每个处理程序都与记录的对象格式相关联

<强>优点

  • 系统高度可扩展。如果你需要比较类型X或Y,只需编写一个处理程序。这实际上与浏览器或编辑器的插件系统相当。

  • 您不会在数据库中存储代码。存储相同类型比较的代码完全违反DRY原则( Don不要重复)。

  • 单元测试。当你有一个包含这些代码的数据库时,我无法想象单元测试是如何工作的。他们真的很痛苦。

<强>缺点

  • 在您真正开始评估数据之前,需要先编写一些代码。

    然而,这种类型的问题实际上是为OOP解决方案而哭泣!它真的教你如何应用和使用OOP。至少在我看来,看到如何只添加一个处理程序为您的应用程序提供全新的功能,这很有趣!

伪码

class EqualityHandler implements Handler
  public function handle($handlerData, $data) {
    // checks for equality and returns true or false
    return true;
  }
}
// TODO Act like Java: EqualityHandler.class (pass type of class)
$app->registerHandler('EqualityHandler');

// loop all rows
foreach ($row as $csvFields) {

  foreach  (retrieveConditions($row) as $condition) {
    handleCondition($condition, $csvFields);
  }

}

function handleCondition($condition, $csvFields) {
  if ($app->getHandler($condition['type'])) {
    return $app->instantiateHandler($condition['type'])->handle($condition, $csvFields);
  }
  else {
    throw new HandlerNotFoundException('...');
  }
}