1

I am creating a calculator in JS, but the calculations are made in PHP. The calculator must be able to process more than 1 operator (ex. 1+2*3-4/5) without using eval() or similar tricks.

After searching a lot, I ended up with this:

if (isset($_POST)) {
    $equation = $_POST["textview"];
}


$stored = $equation;
$components = preg_split('~([*/%+-])~', $stored, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

while (($index = array_search('*', $components)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] * $components[$index + 1]);
}
while (($index = array_search('/', $components)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] / $components[$index + 1]);
}
while (($index = array_search('%', $components)) !== false) {
    array_splice($components, $index - 1, 3, fmod($components[$index - 1], $components[$index + 1]));
}
while (($index = array_search('+', $components)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] + $components[$index + 1]);
}
while (($index = array_search('-', $components)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] - $components[$index + 1]);
}

echo current($components);

It seems to work perfectly, except for one problem: when the result of the calculation is 0, it gives me an error, and doesn't end the "while" loop


Notice: Undefined offset: -1 in C:\xampp\htdocs\***************\component\calculation.php on line 26

Notice: Undefined offset: 1 in C:\xampp\htdocs\****************\component\calculation.php on line 26

In this case, line 26 would be the subtraction (did a 1-1 operation), but it happens with every other calculation that should return a 0.

I have no idea why it happens and how to solve it, so if someone could help me, please, it would be great.

rcoelho14
  • 15
  • 6
  • Possible duplicate of ["Notice: Undefined variable", "Notice: Undefined index", and "Notice: Undefined offset" using PHP](https://stackoverflow.com/questions/4261133/notice-undefined-variable-notice-undefined-index-and-notice-undefined) – aynber Sep 17 '19 at 16:40
  • When `$index` is `0`, `$components[$index - 1]` will try to access `$components[-1]`. – Barmar Sep 17 '19 at 16:41
  • @Barmar what's the way to fix it, then? I really have no idea :| – rcoelho14 Sep 17 '19 at 16:44
  • See https://3v4l.org/IhW94 At the end of the first loop, you've replaced the array of `0=>1, 1=> '-', 2=>1` with `0=>0`, so it breaks. For some odd reason, `array_search('-', [0])` returns 0, which is not false. – aynber Sep 17 '19 at 16:47
  • When I try this with `$stored = "1-1";` I get an infinite loop, not that error. – Barmar Sep 17 '19 at 16:47
  • @aynber Shouldn't the next `array_search()` return `false` so the loop stops? – Barmar Sep 17 '19 at 16:51
  • @Barmar it gives me the infinite loop with that error – rcoelho14 Sep 17 '19 at 16:51
  • Yeah, just realized that I didn't see the error because I'm using a GUI tool that doesn't show anything until the script ends. – Barmar Sep 17 '19 at 16:52
  • @Barmar It should. That's why it's so weird that `'-' == 0`. – aynber Sep 17 '19 at 16:52
  • The fix for this would probably to make sure that `count($components) > 1` in your while check, so that I won't try to run it again when that happens. – aynber Sep 17 '19 at 16:53
  • @aynber holy shit, that actually worked! :D Now I just got to stop PHP from executing any division by 0 (making it return "ERROR" instead) and it's done :D Thank you a lot, both of you! :D – rcoelho14 Sep 17 '19 at 16:58
  • That's not a complete solution. The code will fail whenever any of the partial solutions is `0`. – Barmar Sep 17 '19 at 17:01

1 Answers1

1

The problem is that array_search() is performing loose comparison. When an element of $components is a number, it will convert the search string to a number before comparing. A string that doesn't look like a number is converted to 0, so array_search("-", [0]) returns 0 rather than false (try var_dump('-' == 0, '-' === 0)).

array_search has an optional strict parameter that makes it do strict comparison (like === rather than ==). Adding this to all the array_search calls fixes the problem.

$stored = "1-1";
$components = preg_split('~([*/%+-])~', $stored, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
while (($index = array_search('*', $components, true)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] * $components[$index + 1]);
}
while (($index = array_search('/', $components, true)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] / $components[$index + 1]);
}
while (($index = array_search('%', $components, true)) !== false) {
    array_splice($components, $index - 1, 3, fmod($components[$index - 1], $components[$index + 1]));
}
while (($index = array_search('+', $components, true)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] + $components[$index + 1]);
}
while (($index = array_search('-', $components, true)) !== false) {
    array_splice($components, $index - 1, 3, $components[$index - 1] - $components[$index + 1]);
}

echo current($components);
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Thanks, it works very well! I actually didn't know about that "strict" parameter. Still don't know very well how the array_search works – rcoelho14 Sep 17 '19 at 17:05