Basi Manele
Basi Manele

Reputation: 97

A simpler way to write the calculator class in OOP PHP

I have created a class called Calculator with the add, subtract, multiply and divide function. The calculator is limited to adding two numbers and returning the result. I am relatively new to OOP,would like to get some input on the class, did i take the long route and if i did is there another way to simplify the class.

Here is the code:

class Calculator {
    private $_val1 , $_val2;

    public function __construct($val1, $val2){
        $this->_val1 = $val1;
        $this->_val2 = $val2;
    }

    public function add(){
        return $this->_val1 + $this->_val2;
    }

    public function subtract(){
        return $this->_val1 - $this->_val2;
    }

    public function multiply (){
        return $this->_val1 * $this->_val2;
    }

    public function divide () {
        return $this->_val1 / $this->_val2;
    }
}

$calc = new Calculator(3,4);
echo "<p>3 + 4 = ".$calc->add(). "</p>";

$calc = new Calculator (15,12);
echo "<p>15 - 12 = ".$calc->subtract(). "</p>";

$calc = new Calculator (20,2);
echo "<p> 20 * 2 = ".$calc->multiply(). "</p>";

$calc = new Calculator (20,2);
echo "<p> 20 / 2 = ".$calc ->divide(). "</p>";

Upvotes: 8

Views: 19375

Answers (6)

Touki
Touki

Reputation: 7525

IMHO, you should use Polymorphism.
This Video may help you understanding this principle

Here's my way of thinking.

First, define an interface for any operations you'd need

interface OperationInterface
{
    public function evaluate(array $operands = array());
}

Then, create the calculator holder

class Calculator
{
    protected $operands = array();

    public function setOperands(array $operands = array())
    {
        $this->operands = $operands;
    }

    public function addOperand($operand)
    {
        $this->operands[] = $operand;
    }

    /**
     * You need any operation that implement the given interface
     */
    public function setOperation(OperationInterface $operation)
    {
        $this->operation = $operation;
    }

    public function process()
    {
        return $this->operation->evaluate($this->operands);
    }
}

Then you can define an operation, for example, addition

class Addition implements OperationInterface
{
    public function evaluate(array $operands = array())
    {
        return array_sum($operands);
    }
}

And you would use it like :

$calculator = new Calculator;
$calculator->setOperands(array(4,2));
$calculator->setOperation(new Addition);

echo $calculator->process(); // 6

With that point, if you want to add any new behaviour, or modify an existing one, just create or edit a class.

For example, say you want a Modulus operation

class Modulus implements OperationInterface
{
    public function evaluate(array $operands = array())
    {
        $equals = array_shift($operands);

        foreach ($operands as $value) {
            $equals = $equals % $value;
        }

        return $equals;
    }
}

Then,

$calculator = new Calculator;
$calculator->setOperands(array(4,2));
$calculator->setOperation(new Addition); // 4 + 2

echo $calculator->process(); // 6

$calculator->setOperation(new Modulus); // 4 % 2

echo $calculator->process(); // 0

$calculator->setOperands(array(55, 10)); // 55 % 10

echo $calculator->process(); // 5

This solution allows your code to be a third-party library

If you plan to reuse this code or give it away as a library, the user wouldn't by any case modify your source code.
But what if he wants a Substraction or a BackwardSubstraction method which are not defined ?

He just has to create his very own Substraction class in his project, which implements OperationInterface in order to work with your library.

It's easier to read

When looking in the project architecture it's easier to see a folder like this

- app/
    - lib/
        - Calculator/
            - Operation/
                - Addition.php
                - Modulus.php
                - Substraction.php
            - OperationInterface.php
            - Calculator.php

And immediatly know which file contains the desired behaviour.

Upvotes: 8

Alfwed
Alfwed

Reputation: 3282

I would do something like this

interface Evaluable {
    public function evaluate();
}

class Value implements Evaluable {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function evaluate() {
        return $this->value();
    }
}

class Node implements Evaluable {
    protected $left;
    protected $right;

    public function __construct(Evaluable $left, Evaluable $right) {
        $this->left = $left;
        $this->right = $right;
    }
}

class SumNode extends Node {
    public function evaluate() {
        return $this->left->evaluate() + $this->right->evaluate();
    }
}

$op = new SumNode(new Value(2), new Value(3));
$result = $op->evaluate();

This way you can easyly add new operations

class SubNode extends Node {
    public function evaluate() {
        return $this->left->evaluate() - $this->right->evaluate();
    }
}

And chain operations like this

$sum1 = new SumNode(new Value(5), new Value(3));
$sum2 = new SumNode(new Value(1), new Value(2));
$op = new SubNode($sum1, $sum2);
$result = $op->evaluate();  

Upvotes: 2

RDK
RDK

Reputation: 4560

This task has a lot of solutions, here is one of them:

 <?

class Calculator
{

    /**
     * @var float
     */
    /**
     * @var float
     */
    private $_val1,
        $_val2;

    /**
     * @var int
     */
    private static $_result = 0;

    /**
     * @param $val1
     * @param $val2
     */
    public function __construct($val1 = '', $val2 = '')
    {
        if ((!empty($val1) && !empty($val2)) && (!is_numeric($val1) && !is_numeric($val2))) {
            $this->_val1 = (float)$val1;
            $this->_val2 = (float)$val2;
        }
    }

    /**
     * @param $val1
     */
    public function setVal1($val1)
    {
        $this->_val1 = (float)$val1;
    }

    /**
     * @param $val2
     */
    public function setVal2($val2)
    {
        $this->_val2 = (float)$val2;
    }

    /**
     * @param string $operator
     *
     * @return float|int|string
     */
    public function getResult($operator = '')
    {
        if (is_numeric($this->_val1) && is_numeric($this->_val2)) {
            switch ($operator) {
                case '+':
                    self::$_result = $this->_val1 + $this->_val2;
                    break;
                case '-':
                    self::$_result = $this->_val1 - $this->_val2;
                    break;
                case '*':
                    self::$_result = $this->_val1 * $this->_val2;
                    break;
                case '/':
                    self::$_result = $this->_val1 / $this->_val2;
                    break;
            }
        } else {
            echo 'Alert alert alert)) some of operands not set or not number';
        }
        return self::$_result;
    }
}

And here is nice solution https://gist.github.com/cangelis/1442951

Upvotes: 0

Micha&#235;l Nguyen
Micha&#235;l Nguyen

Reputation: 363

In general, we don't fix value in those kind of class. Your methods should take their 2 values by arguments instead of picking private members.

Like the following:

public function add($v1, $v2)
{
    return $v1 + $v2;
}

Thus, Calculator becomes a tool, and we should not need to allocate this kind of object. That's why Calculators methods should be static.

public static function add($v1, $v2)
{
    return $v1 + $v2;
}

In this way, all you need to call is Calculator::add(1, 2). You can find those kinds of class everywhere. Like Vector, Matrice in math or 3D. Or write to the output or anything like that.

Remember, it is a way to do that, neither the best nor the worst.

Upvotes: 1

Matt
Matt

Reputation: 3848

I don't think a plain calculator is a good example for OOP. An object needs both a set of methods and a set of variables that represent its state, and can be used to differentiate instances of the object. I would suggest trying to make "moody" calculators. A calculator with a happy mood will add 2 to each result, and an angry calculator will subtract 2 from each result.

Upvotes: 2

Andrei Cristian Prodan
Andrei Cristian Prodan

Reputation: 1122

you should probably end up doing something like

$calc = new Calculator();
$calc->sum($x, $y, $z);
$calc->substract($x, $y);
....

Take a look at this example. You can give any number of arguments like this using func_num_args()

<?php
function foo()
{
$numargs = func_num_args();
echo "Number of arguments: $numargs\n";
}

foo(1, 2, 3);   
?>
// output: Number of arguments: 3

Upvotes: 0

Related Questions