BinaryNode.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\ExpressionLanguage\Node;
  11. use Symfony\Component\ExpressionLanguage\Compiler;
  12. /**
  13. * @author Fabien Potencier <fabien@symfony.com>
  14. *
  15. * @internal
  16. */
  17. class BinaryNode extends Node
  18. {
  19. private const OPERATORS = [
  20. '~' => '.',
  21. 'and' => '&&',
  22. 'or' => '||',
  23. ];
  24. private const FUNCTIONS = [
  25. '**' => 'pow',
  26. '..' => 'range',
  27. 'in' => 'in_array',
  28. 'not in' => '!in_array',
  29. ];
  30. public function __construct(string $operator, Node $left, Node $right)
  31. {
  32. parent::__construct(
  33. ['left' => $left, 'right' => $right],
  34. ['operator' => $operator]
  35. );
  36. }
  37. public function compile(Compiler $compiler)
  38. {
  39. $operator = $this->attributes['operator'];
  40. if ('matches' == $operator) {
  41. $compiler
  42. ->raw('preg_match(')
  43. ->compile($this->nodes['right'])
  44. ->raw(', ')
  45. ->compile($this->nodes['left'])
  46. ->raw(')')
  47. ;
  48. return;
  49. }
  50. if (isset(self::FUNCTIONS[$operator])) {
  51. $compiler
  52. ->raw(sprintf('%s(', self::FUNCTIONS[$operator]))
  53. ->compile($this->nodes['left'])
  54. ->raw(', ')
  55. ->compile($this->nodes['right'])
  56. ->raw(')')
  57. ;
  58. return;
  59. }
  60. if (isset(self::OPERATORS[$operator])) {
  61. $operator = self::OPERATORS[$operator];
  62. }
  63. $compiler
  64. ->raw('(')
  65. ->compile($this->nodes['left'])
  66. ->raw(' ')
  67. ->raw($operator)
  68. ->raw(' ')
  69. ->compile($this->nodes['right'])
  70. ->raw(')')
  71. ;
  72. }
  73. public function evaluate(array $functions, array $values)
  74. {
  75. $operator = $this->attributes['operator'];
  76. $left = $this->nodes['left']->evaluate($functions, $values);
  77. if (isset(self::FUNCTIONS[$operator])) {
  78. $right = $this->nodes['right']->evaluate($functions, $values);
  79. if ('not in' === $operator) {
  80. return !\in_array($left, $right);
  81. }
  82. $f = self::FUNCTIONS[$operator];
  83. return $f($left, $right);
  84. }
  85. switch ($operator) {
  86. case 'or':
  87. case '||':
  88. return $left || $this->nodes['right']->evaluate($functions, $values);
  89. case 'and':
  90. case '&&':
  91. return $left && $this->nodes['right']->evaluate($functions, $values);
  92. }
  93. $right = $this->nodes['right']->evaluate($functions, $values);
  94. switch ($operator) {
  95. case '|':
  96. return $left | $right;
  97. case '^':
  98. return $left ^ $right;
  99. case '&':
  100. return $left & $right;
  101. case '==':
  102. return $left == $right;
  103. case '===':
  104. return $left === $right;
  105. case '!=':
  106. return $left != $right;
  107. case '!==':
  108. return $left !== $right;
  109. case '<':
  110. return $left < $right;
  111. case '>':
  112. return $left > $right;
  113. case '>=':
  114. return $left >= $right;
  115. case '<=':
  116. return $left <= $right;
  117. case 'not in':
  118. return !\in_array($left, $right);
  119. case 'in':
  120. return \in_array($left, $right);
  121. case '+':
  122. return $left + $right;
  123. case '-':
  124. return $left - $right;
  125. case '~':
  126. return $left.$right;
  127. case '*':
  128. return $left * $right;
  129. case '/':
  130. if (0 == $right) {
  131. throw new \DivisionByZeroError('Division by zero.');
  132. }
  133. return $left / $right;
  134. case '%':
  135. if (0 == $right) {
  136. throw new \DivisionByZeroError('Modulo by zero.');
  137. }
  138. return $left % $right;
  139. case 'matches':
  140. return preg_match($right, $left);
  141. }
  142. }
  143. public function toArray()
  144. {
  145. return ['(', $this->nodes['left'], ' '.$this->attributes['operator'].' ', $this->nodes['right'], ')'];
  146. }
  147. }