Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Separating simple rules from PHP code

Tags:

php

At the moment I have some PHP which sets a single variable based on the value of other independent variables in a linear format, like so:

$result = 0;

if ($var1 == 'X') {
  $result += 10;
}

if ($var2 < 10) {
  $result += 15;
}
elseif ($var2 > 50) {
  $result -= 50;
}

// more of the same

However, I'd like to be able to express these rules in a less programming-like way, mainly so that someone who doesn't know how to program can add/edit rules, and also because I might want to use the same rules in a Python or Perl script, without having to maintain copies in multiple languages. I could write my own simple language (for want of a better word) and parser, but I'd prefer to use an existing solution as that saves work and increases the likelihood that other people will know how to write rules in it.

Is there a sensible/obvious choice for this sort of task?

like image 685
pwaring Avatar asked Sep 23 '26 04:09

pwaring


2 Answers

I don't think you need a language/parser for this. You could create an expression builder (similar to how one creates email message filter rules) and store the results in a database. This will also allow other languages to access the stored rules.

Users would add comparisons until satisfied, then enter the associated assignment rule.

like image 59
webbiedave Avatar answered Sep 25 '26 17:09

webbiedave


Design a little pseudo-language and convert it to PHP code.

$var1 == 'X': +10
$var2 < 10:   +15
$var2 > 50:   -50

Now you can use the PHP Tokenizer to parse this and convert it to real PHP code. Then you should cache the generated code and include it as a PHP file.

This is a really quick and dirty implementation using my own TokenStream class (but you could easily port that to the native tokenizer):

<?php
    $code =<<<'EOC'
$var1 == 'X': +10

$var2 < 10:   +15
$var2 > 50:   -50
EOC;

    require '../tokenstream/src/TokenStream.php';

    $tokenStream = new TokenStream('<?php ' . $code);
    $code = '';
    foreach ($tokenStream as $i => $token) {
        if ($token->is(T_OPEN_TAG)) {
            $code .= '<?php $result = 0;' . PHP_EOL . 'if (';
        }
        elseif ($token->is(T_WHITESPACE) && preg_match("[\r\n]", $token->content)) {
            $code .= ';' . $token . 'if (';
        }
        elseif ($token->is(T_COLON)) {
            $code .= ') $result += ';
        }
        else {
            $code .= $token;
        }
    }
    $code .= ';';

    echo '<pre>', htmlspecialchars($code), '</pre>';

It is really quick and dirty. You could execute arbitrary code. For a better implementation you would need to implement a state machine and I hadn't got the time right now ;)

Script output:

<?php $result = 0;
if ($var1 == 'X') $result +=  +10;

if ($var2 < 10) $result +=    +15;
if ($var2 > 50) $result +=    -50;
like image 31
NikiC Avatar answered Sep 25 '26 19:09

NikiC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!