Exercise: Calculator Again

Exercise 5 Easy

Prerequisites for the exercise

  1. PHP Control Flow
  2. All previous chapters

Objective

Extend the program created in the previous Rudimentary Calculator exercise to enable recomputation of any operation on two given values.

Description

In the previous Rudimentary Calculator exercise, we constructed a program that could perform one of a given list of operations on two input integers. However, as you many know, it was only possible to do this once.

After the first computation, the program ended and likewise we couldn't continue on with other computations. The only way to do another computation was to rerun the program.

Now in this exercise, you need to make a couple of modifications to the previous program so that it could perform as many computations as the user wants to, and then stop when the user is done with the computations.

The initial inputs and outputs of this program are same as those in the previous exercise.

However, when the first computation is complete with its output (which is again the same as in the previous exercise), you should then ask the user the following question, after leaving a blank line.

Restart? ('y' for yes, 'n' for no): <restart>

If the user inputs 'y', continue repeating the steps of the program after a blank line. In contrast, if the user inputs 'n', halt the program — no more computations could be performed now.

Below shown is a detailed example.

x: 10 y: 50 Operation: a 10 + 50 = 60 Restart? ('y' for yes, 'n' for no): y x: 17 y: 3 Operation: e 17 ** 3 = 4913 Restart? ('y' for yes, 'n' for no): n

Take note of the blank lines in the shell snippet here. You must make sure that your code also has them.

View Solution

New file

Inside the directory you created for this course on PHP, create a new folder called Exercise-5-Calculator-Again and put the .php solution files for this exercise within it.

Solution

First of all, when it's stated that the program should be able to continue on with another such computation, we think of repetition.

What is being repeated over here?

Well, the whole segment of code from the previous exercise is being repeated — asking the user to enter a value for x and y and a value for the operation to perform on them, and then outputting the result of the operation.

And where there's repetition, there's a loop. But which one to use?

Shall we use for or while?

Recall that for is useful to iterate over sequences and ranges, whereas while is more oriented for iteration until some condition doesn't become false.

The second question is that shall we use while or do...while?

Well, let's think about it.

We need to perform the computation at least once. Moreover, it's only after the first computation is complete that we shall prompt the user to specify whether he/she wants to perform another computation.

Altogether, this gives us the hint that we ought to use do...while.

With the loop decided, now we just need to think about what condition to lay out in it.

Let's ask a simple question: when do we need to repeat the computation after we've asked the user to specify whether he/she wants to perform it again?

If the user enters y, it means that we need to repeat. If anything else is input, then we simply don't need to repeat. Hence, we could use an expression to compare the input value against the string 'y' and continue the loop only if both of them are the same.

And this is it.

Here's the complete code:

<?php

do {
   // ...

   if (isset($op_sym))
      echo $x, ' ', $op_sym, ' ', $y, ' = ', $result;
   else
      echo 'Unknown operation.';


   // Restart prompt.
echo "\n\nRestart? ('y' for yes, 'n' for no): ";
$restart = rtrim(fgets(STDIN)); // Blank line before next computation.
echo "\n"; } while ($restart == 'y');

The response to the confirmation prompt is stored in the variable $restart in line 14 and then this variable is used in the iteration condition for while in line 19.

If $restart is equal to 'y' (for yes), the loop continues on. Otherwise, if any other character is input (be that n or anything else), execution jumps out of the loop.

Although the code above has no syntax errors, there is certainly a logical error in there. A logical error is an error in the logic of code i.e. something is being done in the wrong way due to which the output is not what's expected.

Let's see if you can spot the error in the code above.

The error starts to appear after two computations are done, the first with a known operation and the second with an unknown operation.

So assuming that you've tried to find the error, it's time to see the error.

When the first computation ends with a known operation, the variables $op_sym and $result are created.

Next up, we want to perform another computation and, likewise, we enter y in response to the restart computation prompt. This puts on another computation. So far, so good.

Now at this point if the entered operation is unknown, the isset($op_sym) check fails, that's responsible for printing the unknown operation message. This is the problem.

The check fails since $op_sym exists from the very first computation that went well. Ideally, $op_sym should have been deleted after the first computation but it remains there in memory and hence interrupts with the next computation's correct logical execution.

Alright, now that we have spotted the error, it's time to think how to rectify it.

Well there are many ways to fix this problem. Even, in general, when a problem is faced in a piece of code, there is typically more than just one way to solve it.

Here, we'll take the simplest and most intuitive approach without changing much of our existing code.

That is to unset $op_sym at the end of each computation. In this way, the computation would go correctly itself and, at the same time, not interrupt the correctness of the next computation.

Great!

Here's the complete code:

<?php

do {
   // ...

   if (isset($op_sym))
      echo $x, ' ', $op_sym, ' ', $y, ' = ', $result;
   else
      echo 'Unknown operation.';


   // Restart prompt.
echo "\n\nRestart? ('y' for yes, 'n' for no): ";
$restart = rtrim(fgets(STDIN)); // Blank line before next computation.
echo "\n"; } while ($restart == 'y');

This completes our exercise!