Dynamic calculations php

Asked

Viewed 1,185 times

4

Is it possible to make a calculation in php, and my mathematical operations are in a variable? Ex:

$operacao = '+';
$valor1 = 10;
$valor2 = 10;
$calculo = $valor1 .$operacao. $valor2;

It would have to give Result 20, but by default PHP concatenates bringing me a string:

"10 + 10";
  • 1

    With only if else or switch example: if($operação === '+')

  • Yes, it would facilitate a lot if it existed, because there are several calculations and this way will quadruple the number of lines.

  • The cited Eval is not very recommendable

  • Is there any other way to do this @Ivcs?

  • Better a parser than an Eval

  • http://answall.com/questions/156657/como-retr-um-resultado-v%C3%A1lido-a-from-an-opera%C3%A7%C3%A3o-em-php

Show 1 more comment

2 answers

4


Yes, it has the function val() (eval - Runs a string as PHP code).

$operacao = '+';
$valor1 = 10;
$valor2 = 10;
$calculo = "$valor1 $operacao $valor2";
eval('echo '.$calculo.';');

DEMO

Function:

function soma($n1,$n2)
{
    return $n1+$n2;
}

eval('echo soma(10,20);');

DEMO

Observing: Particularly speaking, I wouldn’t make the sum so, but once I had to use the val() to solve a particular problem where the return came a function in a string and had to execute, used the val() and solved that particular problem.

Reference:

val

PHP Eval() function - Utilities

  • If you want to return to a variable, follow the example => $calculus = Eval("Return $valor1 $operation $valor2;");

  • The Eval runs all the instruction, so I even put inside the eval the echo and in the end ;, to add and show the result.

  • @Lucaoa I made an edition for you to see what would be the call of a text itself!

  • Got it, @João. I was curious and also went to search. I found it interesting. It would be impossible to use this way (to add) or I’m wrong ?

  • @Lucaoa is like I said in the remark: it will depend even on the scenario, but, particularly I would do otherwise, in the example I gave and it was real, a webservice returned a function within a string to perform that function I had to give an Eval to work, there was no other way, if you have simpler forms I believe it is much better, but, it is like learning, the question was very good.

  • Great explanation, I believe that it would only be valid to give an explanation of the care when using the eval(), because the same will "read" the variable and try to execute a command from it, if not used well can open giant security loopholes;

  • 1

    @Lucasqueirozribeiro serves it Eval is either good or bad ?

  • @Guilhermenascimento is a good explanation, I just think is worth the warning in the reply and not in the comments beyond that the link can break, because the eval is not a good guy or bandit, just needs certain care to not have future problems (like many other functions and features) :)

  • 1

    @Lucasqueirozribeiro You can link in the comments and give an up on it, so it stands out, note that the author of the reply does not even have more account on the site, there is only the answer.

  • @Guilhermenascimento True, had not seen this detail

Show 5 more comments

2

I do not disagree with the use of eval, the problem is that if you do not say the data processing can occur problems in the input values which will go from being a mathematical operation to being a code injection.

Yet a simple "parser" can solve, an example with preg_match_all would be so:

preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
var_dump($output[0]);

It extracts all integer values, with floating point and simple operators, of course it is still possible to inject invalid characters, in case do an input check, thus:

if (preg_match('#^(\d|\d\.\d)([\d\+\-\s\/\*]+|\d+\.\d+)(\d|\d\.\d)+$#', $input) > 0) {

    preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
    var_dump($output[0]);
}

We’ll still have the problem of people doing calculations like this:

2 2 3 + - /

But you can solve by checking in the loop the last value, a complete example I did:

<?php

class SimpleMath
{
    private static function subcalc($a, $b, $operator)
    {
        switch ($operator)
        {
            case '-':
                return $a - $b;
            break;
            case '+':
                return $a + $b;
            break;
            case '*':
                return $a * $b;
            break;
            case '/':
                return $a / $b;
            break;
        }
    }

    public static function parse($input)
    {
        $input = trim($input);

        if (preg_match('#^(\d|\d\.\d)([\d\+\-\s\/\*]+|\d+\.\d+)(\d|\d\.\d)+$#', $input) > 0) {
            preg_match_all('#(\d\.\d+|\d+|[\+\-\/\*])#', $input, $output);
            $pre = $output[0];
            $j = count($pre);
            $operator = null;
            $final = null;

            for ($i = 0; $i < $j; $i++) {
                var_dump($pre[$i]);

                switch ($pre[$i]) {
                    case '-':
                    case '+':
                    case '*':
                    case '/':
                        if ($op !== null) {
                            //Se já houver um operador "preparado" e tentar adicionar outro força um erro
                            throw new Exception('Erro na ordem dos operadores');
                        }

                        $op = $pre[$i];
                    break;
                    default:
                        if ($final === null){
                            $final = $pre[$i];
                        } else if ($operator === null) {
                            //Se o anterior não era um operador força um erro
                            throw new Exception('Erro, falta um operador');
                        } else if (is_numeric($pre[$i])) {
                            $final = self::subcalc($final, $pre[$i], $operator);
                            //Remove operador usado
                            $operator = null;
                        } else {
                            //Se o numero na sequencia for invalido força um erro
                            throw new Exception('Formato do numero é invalido');
                        }
                }
            }

            return $final;
        } else {
            throw new Exception('Input invalido');
        }
    }
}

var_dump( SimpleMath::parse('2 * 2 - 1') );

It does not work for advanced calculations, but just you adapt and add conditions and or operators, also have the case to use the parentheses as soon as possible I will create an example that supports something like (1 * 2) - (3 /4)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.