1

I'm currently working on a PHP application that needs to solve equations that may, or may not, have a ternary operator.

For example, after replacing my variables in the equation, we are left with the following string:

$eq = '(3.07 > 10 ? 1.93 * 10 : 3.07 * 1.93)';

We were previously using eval() (which would obviously work), but moved to an EOS package from PHP Classes (https://www.phpclasses.org/package/2055-PHP-Solve-equations-with-multiple-variables.html) because of the security issues with eval().

The EOS class doesn't interpret the ternary operator, and I don't want to go back to eval(), so what are my options here? Is there a better PHP EOS library that I can use somewhere?

Nate
  • 11
  • 1
  • Well ternary isn't something mathematical. It's just used in programming as far as I know. You'll probably need to make your own parser to make the math. – Phiter Aug 24 '18 at 19:57
  • I'd prefer not to build my own parser, if I can avoid it. My buddy told me about ast.literal_eval() in Python, which sounded promising, but there doesn't seem to be a PHP equivalent, which is very disappointing. @Don'tPanic The parser doesn't require the surrounding (). I just happened to enter the equation into the DB with the surrounding (). Why? – Nate Aug 24 '18 at 20:17
  • I was just wondering if I should trim them off for my answer. But I decided to just answer it without them. – Don't Panic Aug 24 '18 at 20:19
  • Also, if you've found something in Python that could do the job, but your main project is in PHP, it's possible for PHP to pass the expression to Python to evaluate it. – Don't Panic Aug 24 '18 at 20:24
  • @Nate, "ternary" operations/if structures won't work with ast.literal_eval either. – Devon Bessemer Aug 24 '18 at 20:25

1 Answers1

1

Assuming there's just one ternary, you could break up the string into the separate parts of the ternary expression and evaluate the parts separately.

$eq = '3.07 > 10 ? 1.93 * 10 : 3.07 * 1.93';

preg_match('/(.+)\?(.+):(.+)/', $eq, $parts);

if (isset($parts[3])) {
  $result = Parser::solve($parts[1]) ? Parser::solve($parts[2]) : Parser::solve($parts[3]);
} else {
  $result = Parser::solve($eq);
}

If there's more than one ternary, you could probably still could do it if you were better at regex than me. :)

I admit this approach is a bit naive, I can think of various things that would break it pretty easily, e.g. a parenthetical ternary sub-expression, but it could work for simple examples like the one in your question.

Don't Panic
  • 41,125
  • 10
  • 61
  • 80