I was just wondering if PHP has a function that can take a string like 2-1 and produce the arithmetic result of it?

Or will I have to do this manually with explode() to get the values left and right of the arithmetic operator?

  • Where do you get this expression at?– zerkmsFeb 20 '11 at 13:33
  • 4
    /me casts million of answers with eval– zerkmsFeb 20 '11 at 13:33
  • 1
    it is super effective!– FemarefFeb 20 '11 at 13:34
  • 1
    @Femaref: It is one more vulnerability! ;-)– zerkmsFeb 20 '11 at 13:34
  • 1
    I meant the cast, not the function. Of course, eval should be used sparsely.– FemarefFeb 20 '11 at 13:35

I know this question is old, but I came across it last night while searching for something that wasn't quite related, and every single answer here is bad. Not just bad, very bad. The examples I give here will be from a class that I created back in 2005 and spent the past few hours updating for PHP5 because of this question. Other systems do exist, and were around before this question was posted, so it baffles me why every answer here tells you to use eval, when the caution from PHP is:

The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.

Before I jump in to the example, the places to get the class I will be using is on either PHPClasses or GitHub. Both the eos.class.php and stack.class.php are required, but can be combined in to the same file.

The reason for using a class like this is that it includes and infix to postfix(RPN) parser, and then an RPN Solver. With these, you never have to use the eval function and open your system up to vulnerabilities. Once you have the classes, the following code is all that is needed to solve a simple (to more complex) equation such as your 2-1 example.

require_once "eos.class.php";$equation="2-1";$eq=new eqEOS();$result=$eq->solveIF($equation);

That's it! You can use a parser like this for most equations, however complicated and nested without ever having to resort to the 'evil eval'.

Because I really don't want this only only to have my class in it, here are some other options. I am just familiar with my own since I've been using it for 8 years. ^^

Wolfram|Alpha API
Sage
A fairly bad parser
phpdicecalc

Not quite sure what happened to others that I had found previously - came across another one on GitHub before as well, unfortunately I didn't bookmark it, but it was related to large float operations that included a parser as well.

Anyways, I wanted to make sure an answer to solving equations in PHP on here wasn't pointing all future searchers to eval as this was at the top of a google search. ^^

  • Thx for an elaborated answer, I marked your answer as correct now as you're right the eval shouldn't be used, but at the time I was just looking for a quick solution.– NikolaApr 18 '13 at 5:27
  • Haha, understandable.=] And thanks. I didn't know if you still visited the question or anything, just wanted a non-eval answer thrown in with the pack ^^ And you are welcome! Hopefully it was useful.=]– JonApr 18 '13 at 16:53
  • I get a notification if anyone posts an answer or comment on a question which I posted, so I took a look immediately. Yeah, it's good point - thx!– NikolaApr 18 '13 at 17:00
  • In the event that the math string contains a $variable, is there anyway to make these variables available to the parser? Perhaps as a second parameter (an array of indexed values)? I am going to look at your code to see if I can not find a way to do this.– MikeJan 6 '15 at 23:44
  • @MichaelJMulligan Variable stored within your code, yes, if you pass the value you the parser. Look at the (GitHub([github.com/jlawrence11/Classes] README.md for more information. ^^– JonJan 7 '15 at 7:15
$operation='2-1';eval("\$value=\"$operation\";");

or

$value=eval("return ($op);");
  • 1
    The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.– MERT DOĞANOct 12 '16 at 8:56

This is one of the cases where eval comes in handy:

$expression='2 - 1';eval( '$result=(' . $expression . ');' );echo $result;

    You can use BC Math arbitrary precision

    echo bcsub(5, 4); // 1echo bcsub(1.234, 5); // 3echo bcsub(1.234, 5, 4); // -3.7660

    http://www.php.net/manual/en/function.bcsub.php

    • Excellent, better than I could've imagine it!– MelsiJan 20 '13 at 7:06

    In this forum someone made it without eval. Maybe you can try it? Credits to them, I just found it.

    function calculate_string( $mathString ) {$mathString=trim($mathString); // trim white spaces$mathString=ereg_replace ('[^0-9\+-\*\/\(\) ]', '', $mathString); // remove any non-numbers chars; exception for math operators$compute=create_function("", "return (" . $mathString . ");" );return 0 + $compute();}$string=" (1 + 1) * (2 + 2)";echo calculate_string($string); // outputs 8 
    • 3
      Caution Create_function: This function internally performs an eval() and as such has the same security issues as eval(). Additionally it has bad performance and memory usage characteristics. If you are using PHP 5.3.0 or newer a native anonymous function should be used instead.– DrunkWolfNov 17 '15 at 12:35

    Also see this answer here: Evaluating a string of simple mathematical expressions

    Please note this solution does NOT conform to BODMAS, but you can use brackets in your evaluation string to overcome this.

    function callback1($m) {return string_to_math($m[1]);}function callback2($n,$m) {$o=$m[0];$m[0]=' ';return $o=='+' ? $n+$m : ($o=='-' ? $n-$m : ($o=='*' ? $n*$m : $n/$m));}function string_to_math($s){ while ($s !=($t=preg_replace_callback('/\(([^()]*)\)/','callback1',$s))) $s=$t;preg_match_all('![-+/*].*?[\d.]+!', "+$s", $m);return array_reduce($m[0], 'callback2');}echo string_to_match('2-1'); //returns 1
    • And how about addition? I`ve got a result of 5+5=5, + was omitted while parsing((– JackAug 19 '16 at 16:50

    Here is a somewhat verbose bit of code I rolled for another SO question. It does conform to BOMDAS without eval(), but is not equipped to do complex/higher-order/parenthetical expressions. This library-free approach pulls the expression apart and systematically reduces the array of components until all of the operators are removed. It certainly works for your sample expression: 2-1 ;)

    1. preg_match() checks that each operator has a numeric substring on each side.
    2. preg_split() divides the string into an array of alternating numbers and operators.
    3. array_search() finds the index of the targeted operator, while it exists in the array.
    4. array_splice() replaces the operator element and the elements on either side of it with a new element that contains the mathematical result of the three elements removed.

    ** updated to allow negative numbers **

    Code: (Demo)

    $expression="-11+3*1*4/-6-12";if(!preg_match('~^-?\d*\.?\d+([*/+-]-?\d*\.?\d+)*$~',$expression)){echo "invalid expression";}else{$components=preg_split('~(?<=\d)([*/+-])~',$expression,NULL,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);var_export($components); // ['-11','+','3','*','1','*','4','/','-6','-','12']while(($index=array_search('*',$components))!==false){array_splice($components,$index-1,3,$components[$index-1]*$components[$index+1]);var_export($components);// ['-11','+','3','*','4','/','-6','-','12']// ['-11','+','12','/','-6','-','12']}while(($index=array_search('/',$components))!==false){array_splice($components,$index-1,3,$components[$index-1]/$components[$index+1]);var_export($components); // [-'11','+','-2','-','12']}while(($index=array_search('+',$components))!==false){array_splice($components,$index-1,3,$components[$index-1]+$components[$index+1]);var_export($components); // ['-13','-','12']}while(($index=array_search('-',$components))!==false){array_splice($components,$index-1,3,$components[$index-1]-$components[$index+1]);var_export($components); // [-25]}echo current($components); // -25}

    Here is a demo of the BOMDAS version that uses php's pow() when ^ is encountered between two numbers (positive or negative).

    I don't think I'll ever bother writing a version that handles parenthetical expressions ... but we'll see how bored I get.

    • if(!preg_match('~^\d*\.?\d+([*/+-]\d*\.?\d+)*$~',$expression)) throw new \Exception("Invalid expression: $expression"); 142/44 : Invalid expression– vivoconunxinoAug 18 '17 at 9:54
    • @vivoconunxino I am going to be away from my computer for the night, but if you create a sandbox.onlinephpfunctions.com link for me, I'll have a look and try to help you isolate the problem. What php version are you on?– mickmackusaAug 18 '17 at 10:20
    • Hello mickmackusa, php 7.1. BTW, I did it with: if(!preg_match('~^\d*([*/+-]\d*\.?\d+)*$~',$expression)) throw new \Exception("Invalid expression: $expression");– vivoconunxinoAug 18 '17 at 10:26
    • It doesn't seem to like the variable $expression. Is it declared? What is it?– mickmackusaAug 18 '17 at 11:05

    Your Answer

     

    By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

    Not the answer you're looking for? Browse other questions tagged or ask your own question.