douxiong2999 2014-01-10 20:57
浏览 137

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

As background, I'm writing php code that parses csv files and does something with each row of each csv file. What that "something" is depends on the values in the row. It's easy to test the values with an "if" structure, however, hardcoding the conditions is not optimal for two reasons:

  1. there are several hundred possible conditions to be tested. That's just to begin with. More conditions will be added in the future.

  2. Each csv row does not need to be tested for each condition; as soon as a condition for a row evaluates to true, no further conditions need be evaluated.

Ideally, for my situation, the "if" conditions would be stored in a postgres table, put into a string variable one by one, and then each variable would tested by a single if structure (inside a loop of some kind) until a condition evaluates to true.

Simplified example:

$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
}

This question was essentially asked at

PHP - if condition inside string

There were three basic answers:

  1. You could use eval(), but DON'T! It's evil! (agreed)
  2. Hard-code all the conditions (not optimal for reasons provide above and others)
  3. Store the conditions in a schema (which is what I'm doing) and then parse and convert to php code.

Solution 3 is generally what I'm looking for, but second part seems inefficient and unnecessarily complex. After all, why build up php code from numerous strings (of an unknown number, by the way, which complicates storage in postgres) when it seems so much easier to just store and then evaluate the single string you need?

Is there a way to do that?

Many thanks for the responses so far. ComFreek, thanks to you in particular for the detailed response. The solution you suggest may be just what I need, but frankly, I don't have the experience to know immediately if that's the case. I'll definitely spend time trying to understand what you're saying. Hopefully, it will solve my problem.

In case it doesn't, and in the meantime, to answer a few questions others asked:

1) the if conditions will not usually be simple. Many will contain multiple and compound AND and OR tests. A sample condition, in pseudo-code, might be: ( field2=="BUY" AND ( strpos("REINVEST DIVIDEND", field6) OR strpos("CASH MERGER, field6) ) AND field2!="TTXY" AND field3>0 ).

2) The CSV files come from numerous financial institutions. They contain much the same information, but each has unique data, and all of them have the data in different locations. What's more they express the data differently. In some, a payment is indicated by a negative number; in others, by a positive number. Some have separate fields for deposits and withdrawals; some indicate deposits and withdrawals with a code in another column. And so on. The code needs to determine the nature of the transaction (credit card purchase, check, stock buy or sell, retirement contribution, and on and on) and then, if it can, assign the correct debit/credit account numbers (from a chart of accounts) to that transaction. Altogether, there are hundreds of possible conditions, likely to become thousands. (In case anyone is wondering, the code can determine the institution a particular csv file comes from and will test the transactions in that file only against conditions relevant to that institution.)

3) The code needs to be flexible enough to easily (in other words, without having to write new code) allow for new tests to be added in the future. For me, being able to add a new condition to a postgres table (which will then be another test for the code to check) is sufficient flexibility.

To try to answer Phil's questions and comments (which I may not be understanding correctly):

1) I know what preg_match is, but haven't really explored what it can do, so it may in fact be the answer to my problem. I'll check it out.

2) currently, the code does not group transactions (which is to say a single row from a single csv file); rather, it looks at each row, determines what it is, then stores it an additional data in appropriate postgres tables, then moves to the next row. There are certain "types" of transactions (say credit card purchases) but they're never grouped for further processing.

3) Each transaction should satisfy one and only condition (though that condition may be complex).

4) With regard to matching the entire string, unless I'm missing something (very possible), it's not that simple. For example, let's say a given transaction is a stock purchase. The code can determine that by seeing that "action" field contains the word "Buy" AND the "quantity" field is greater than zero (one or the other of these conditions alone might not be enough to be certain the transaction is a stock purchase), but the "ticker" field could be any of thousands of strings that aren't known in advance--"GOOG", "MSFT", "KO" or whatever.

Again, thanks to all for the responses so far.

  • 写回答

1条回答 默认 最新

  • douxitao8170 2014-01-10 21:06
    关注

    Summary: build an extensible system of handlers for specific comparision types, and store related data in the database.

    You need:

    • Well-known types of conditions
    • An extensible system of registerable handlers which deal with specific types of conditions (e.g. EqualityHandler, StringLengthComparisionHandler)
    • Each handler is associated with a documented object format

    Advantages:

    • The system is highly extensible. If you ever need comparison type X or Y, just write a handler. This is really comparable with a plugin system of a browser or editor.

    • You don't store code in the database. Storing code for equal types of comparison is totally against the DRY principle (Don't repeat yourself).

    • Unit tests. I cannot imagine how unit tests would work when you have a database containing those codes. They would be really painful.

    Disadvantages:

    • It requires you to write some code before you can actually start evaluating your data.

      However, this type of problem is virtually crying for an OOP solution! It really teaches you how OOP can be applied and used. At least in my opinion, it is fun to see how only adding one handler gives your application whole new functionalities!

    Pseudo code:

    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('...');
      }
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥20 使用Photon PUN2解决游戏得分同步的问题
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥30 BC260Y用MQTT向阿里云发布主题消息一直错误
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据
  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 Centos / PETGEM
  • ¥15 划分vlan后不通了