Completed
Push — master ( 2a128c...18787f )
by Alexey
02:20
created

Calc::calc()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
ccs 0
cts 17
cp 0
rs 8.8571
cc 6
eloc 14
nc 6
nop 3
crap 42
1
<?php
2
3
/**
4
 * Calc.php
5
 *
6
 * @date 28.03.2015 0:54:24
7
 * @copyright Sklyarov Alexey <[email protected]>
8
 */
9
10
namespace Sufir\Calc;
11
12
use Sufir\Calc\Token\AbstractToken;
13
14
/**
15
 * Calc
16
 *
17
 * Description of Calc
18
 *
19
 * @author Sklyarov Alexey <[email protected]>
20
 * @package Sufir\Calc
21
 */
22
class Calc
23
{
24
    protected $functions = [];
25
26
    protected $variables = [];
27
28
    /**
29
     *
30
     * @param \Sufir\Calc\Token\AbstractToken[] $tokens
31
     */
32
    public function evaluate(array $tokens)
33
    {
34
        $stack = new \SplStack;
35
        foreach ($tokens as $token) {
36
            // Если на вход подан операнд, он помещается на вершину стека
37
            if ($token->isNumber()) {
38
                $stack->push($token);
39
40
                // Если на вход подан знак операции
41
            } elseif ($token->isOperator()) {
42
                if ($stack->count() < 2) {
43
                    throw new \Exception('Ошибочка вышла! Недостаточно операндов для бинарного оператора: ' . $token);
44
45
                // операция выполняется над требуемым количеством значений,
46
                // извлечённых из стека, взятых в порядке добавления
47
                } elseif ($stack->count() > 1) {
48
                    $second = $stack->pop();
49
                    $first = $stack->pop();
50
51
                    $result = $this->calc((string) $token, (string) $first, (string) $second);
52
53
                    // Результат выполненной операции кладётся на вершину стека
54
                    $stack->push($result);
55
                }
56
57
                // Если на вход подана функция
58
            } elseif ($token->isFunction()) {
59
                if (!isset($this->functions[$token->getValue()])) {
60
                    throw new \Exception('Не найдена функция: ' . $token->getValue());
61
                }
62
63
                $countOfArguments = $this->functions[$token->getValue()]['args'];
64
65
                if ($stack->count() < $countOfArguments) {
66
                    throw new \Exception('Ошибочка вышла! Недостаточно аргументов для функции: ' . $token);
67
                }
68
69
                $arguments = array();
70
71
                for ($idx = 0; $idx < $countOfArguments; $idx++) {
72
                    $arguments[] = ((string) $stack->pop()) - 0;
73
                }
74
75
                $arguments = array_reverse($arguments);
76
77
                $result = call_user_func_array($this->functions[$token->getValue()]['func'], $arguments);
78
79
                $stack->push($result);
80
            }
81
        }
82
83
        return $stack->top();
84
    }
85
86
    /**
87
     *
88
     * @param string $name
89
     * @param \Closure $callable
90
     * @return \Sufir\Calc\Calc
91
     */
92 View Code Duplication
    public function registerFunction($name, \Closure $callable)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    {
94
        $objReflector = new \ReflectionObject($callable);
95
        $reflector = $objReflector->getMethod('__invoke');
96
        $parameters = $reflector->getParameters();
97
98
        $this->functions[$name] = array(
99
            'args' => count($parameters),
100
            'func' => $callable,
101
        );
102
103
        return $this;
104
    }
105
106
    /**
107
     *
108
     * @param string $name
109
     * @param \Closure $callable
0 ignored issues
show
Bug introduced by
There is no parameter named $callable. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
110
     * @return \Sufir\Calc\Calc
111
     */
112 View Code Duplication
    public function registerVariable($name, $value)
0 ignored issues
show
Unused Code introduced by
The parameter $value is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
113
    {
114
        $objReflector = new \ReflectionObject($callable);
0 ignored issues
show
Bug introduced by
The variable $callable does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
115
        $reflector = $objReflector->getMethod('__invoke');
116
        $parameters = $reflector->getParameters();
117
118
        $this->functions[$name] = array(
119
            'args' => count($parameters),
120
            'func' => $callable,
121
        );
122
123
        return $this;
124
    }
125
126
    /**
127
     * @param string $operator
128
     * @param integer|float $firstOperand
129
     * @param integer|float $secondOperand
130
     * @return int
131
     */
132
    protected function calc($operator, $firstOperand, $secondOperand)
1 ignored issue
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
133
    {
134
        switch ($operator) {
135
            case '^':
136
                return pow($firstOperand, $secondOperand);
137
            case '*':
138
                return $firstOperand * $secondOperand;
139
            case '/':
140
                return $firstOperand / $secondOperand;
141
            case '+':
142
                return $firstOperand + $secondOperand;
143
            case '-':
144
                return $firstOperand - $secondOperand;
145
            default:
146
                return 0;
147
        }
148
    }
149
}
150