Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/wbs24.ozonexport/lib/ |
Upload File : |
<?php namespace Wbs24\Ozonexport; /** * Класс вычисляет значение по формуле, также умеет обрабатывать простое тернарное выражение (условие ? выражение1 : выражение2) * Под условием могут подразумеваться простые логические сравнения > < = !=, а также проверка на булево значение */ class CalcExpression { public function run($initialStatement) { if ($this->isContainCompare($initialStatement)) { list($condition, $statements) = explode('?', $initialStatement); list($statement1, $statement2) = explode(':', $statements); $conditionResult = $this->getConditionResult($condition); $statement = $conditionResult ? $statement1 : $statement2; } else { $statement = $initialStatement; } $result = $this->calc($statement); return $result; } protected function isContainCompare($statement) { return ( substr_count($statement, '?') == 1 && substr_count($statement, ':') == 1 && strpos($statement, '?') < strpos($statement, ':') ); } protected function getConditionResult($condition) { $operators = [ '>=', '<=', '>', '<', '!=', '=', ]; $result = null; foreach ($operators as $operator) { if (substr_count($condition, $operator) == 1) { list($left, $right) = explode($operator, $condition); $leftResult = $this->calc($left); $rightResult = $this->calc($right); switch ($operator) { case '>=': $result = ($leftResult >= $rightResult); break; case '<=': $result = ($leftResult <= $rightResult); break; case '>': $result = ($leftResult > $rightResult); break; case '<': $result = ($leftResult < $rightResult); break; case '!=': $result = ($leftResult != $rightResult); break; case '=': $result = ($leftResult == $rightResult); break; } break; } } if ($result === null) $result = ($this->calc($condition) > 0) ? true : false; return $result; } // модифицированный вариант с https://ru.stackoverflow.com/questions/454598/ protected function calc($statement) { $result = false; if (!is_string($statement)) { return $result; // Wrong type } $calcQueue = []; $operStack = []; $operPriority = [ '(' => 0, ')' => 0, '+' => 1, '-' => 1, '*' => 2, '/' => 2, ]; $token = ''; foreach (str_split($statement) as $char) { // Если цифра, то собираем из цифр число if ( ($char >= '0' && $char <= '9') || (is_numeric($token) && strpos($token, '.') === false && $char == '.') ) { $token .= $char; } else { // Если число накопилось, сохраняем в очереди вычисления if (strlen($token)) { array_push($calcQueue, $token); $token = ''; } // Если найденный символ - операция (он есть в списке приоритетов) if (isset($operPriority[$char])) { if (')' == $char) { // Если символ - закрывающая скобка, переносим операции из стека в очередь вычисления пока не встретим открывающую скобку while (!empty($operStack)) { $oper = array_pop($operStack); if ('(' == $oper) { break; } array_push($calcQueue, $oper); } if ('(' != $oper) { // Упс! А открывающей-то не было return $result; // Unexpected ")" } } else { // Встретили операцию кроме скобки. Переносим операции с меньшим приоритетом в очередь вычисления while (!empty($operStack) && '(' != $char) { $oper = array_pop($operStack); if ($operPriority[$char] > $operPriority[$oper]) { array_push($operStack, $oper); break; } if ('(' != $oper) { array_push($calcQueue, $oper); } } // Кладем операцию на стек операций array_push($operStack, $char); } } elseif (strpos(' ', $char) !== false) { // Игнорируем пробелы (можно добавить что еще игнорируем) } else { // Встретили что-то непонятное (мы так не договаривались) return $result; // Unexpected symbol } } } // Вроде все разобрали, но если остались циферки добавляем их в очередь вычисления if (strlen($token)) { array_push($calcQueue, $token); $token = ''; } // ... и оставшиеся в стеке операции if (!empty($operStack)) { while ($oper = array_pop($operStack)) { if ('(' == $oper) { // ... кроме открывающих скобок. Это верный признак отсутствующей закрывающей return $result; // Unexpected "(" } array_push($calcQueue, $oper); } } $calcStack = array(); // Теперь вычисляем все то, что напарсили foreach ($calcQueue as $token) { switch ($token) { case '+': $arg2 = array_pop($calcStack); $arg1 = array_pop($calcStack); array_push($calcStack, $arg1 + $arg2); break; case '-': $arg2 = array_pop($calcStack); $arg1 = array_pop($calcStack); array_push($calcStack, $arg1 - $arg2); break; case '*': $arg2 = array_pop($calcStack); $arg1 = array_pop($calcStack); array_push($calcStack, $arg1 * $arg2); break; case '/': $arg2 = array_pop($calcStack); $arg1 = array_pop($calcStack); array_push($calcStack, $arg1 / $arg2); break; default: array_push($calcStack, $token); } } return array_pop($calcStack); } }