bug #10338 [ExpressionLanguage] Fixed evaluation of short circuit operators (florianv)

This PR was submitted for the 2.4-dev branch but it was merged into the 2.4 branch instead (closes #10338).

Discussion
----------

[ExpressionLanguage] Fixed evaluation of short circuit operators

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

Commits
-------

fba0a40 [ExpressionLanguage] Fixed evaluation of short circuit operators
This commit is contained in:
Fabien Potencier 2014-02-27 14:31:10 +01:00
commit 4986f6db46
2 changed files with 52 additions and 4 deletions

View File

@ -83,9 +83,10 @@ class BinaryNode extends Node
{
$operator = $this->attributes['operator'];
$left = $this->nodes['left']->evaluate($functions, $values);
$right = $this->nodes['right']->evaluate($functions, $values);
if (isset(self::$functions[$operator])) {
$right = $this->nodes['right']->evaluate($functions, $values);
if ('not in' == $operator) {
return !call_user_func('in_array', $left, $right);
}
@ -96,10 +97,15 @@ class BinaryNode extends Node
switch ($operator) {
case 'or':
case '||':
return $left || $right;
return $left || $this->nodes['right']->evaluate($functions, $values);
case 'and':
case '&&':
return $left && $right;
return $left && $this->nodes['right']->evaluate($functions, $values);
}
$right = $this->nodes['right']->evaluate($functions, $values);
switch ($operator) {
case '|':
return $left | $right;
case '^':

View File

@ -12,7 +12,6 @@
namespace Symfony\Component\ExpressionLanguage\Tests;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ParsedExpression;
class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase
{
@ -54,4 +53,47 @@ class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals('constant("PHP_VERSION")', $expressionLanguage->compile('constant("PHP_VERSION")'));
}
/**
* @dataProvider shortCircuitProviderEvaluate
*/
public function testShortCircuitOperatorsEvaluate($expression, array $values, $expected)
{
$expressionLanguage = new ExpressionLanguage();
$this->assertEquals($expected, $expressionLanguage->evaluate($expression, $values));
}
/**
* @dataProvider shortCircuitProviderCompile
*/
public function testShortCircuitOperatorsCompile($expression, array $names, $expected)
{
$result = null;
$expressionLanguage = new ExpressionLanguage();
eval(sprintf('$result = %s;', $expressionLanguage->compile($expression, $names)));
$this->assertSame($expected, $result);
}
public function shortCircuitProviderEvaluate()
{
$object = $this->getMockBuilder('stdClass')->setMethods(array('foo'))->getMock();
$object->expects($this->never())->method('foo');
return array(
array('false and object.foo()', array('object' => $object), false),
array('false && object.foo()', array('object' => $object), false),
array('true || object.foo()', array('object' => $object), true),
array('true or object.foo()', array('object' => $object), true),
);
}
public function shortCircuitProviderCompile()
{
return array(
array('false and foo', array('foo' => 'foo'), false),
array('false && foo', array('foo' => 'foo'), false),
array('true || foo', array('foo' => 'foo'), true),
array('true or foo', array('foo' => 'foo'), true),
);
}
}