10000 [ExpressionLanguage] Deprecate loose comparisons when using the "in" … · symfony/symfony@9260e92 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9260e92

Browse files
[ExpressionLanguage] Deprecate loose comparisons when using the "in" operator
1 parent 4b33917 commit 9260e92

File tree

5 files changed

+46
-10
lines changed

5 files changed

+46
-10
lines changed

src/Symfony/Component/ExpressionLanguage/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Add `enum` expression function
8+
* Deprecate loose comparisons when using the "in" operator
89

910
6.2
1011
---

src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php

+21-5
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ class BinaryNode extends Node
3030
private const FUNCTIONS = [
3131
'**' => 'pow',
3232
'..' => 'range',
33-
'in' => 'in_array',
34-
'not in' => '!in_array',
33+
'in' => '\\'.self::class.'::inArray',
34+
'not in' => '!\\'.self::class.'::inArray',
3535
'contains' => 'str_contains',
3636
'starts with' => 'str_starts_with',
3737
'ends with' => 'str_ends_with',
@@ -101,7 +101,7 @@ public function evaluate(array $functions, array $values)
101101
$right = $this->nodes['right']->evaluate($functions, $values);
102102

103103
if ('not in' === $operator) {
104-
return !\in_array($left, $right);
104+
return !self::inArray($left, $right);
105105
}
106106
$f = self::FUNCTIONS[$operator];
107107

@@ -143,9 +143,9 @@ public function evaluate(array $functions, array $values)
143143
case '<=':
144144
return $left <= $right;
145145
case 'not in':
146-
return !\in_array($left, $right);
146+
return !self::inArray($left, $right);
147147
case 'in':
148-
return \in_array($left, $right);
148+
return self::inArray($left, $right);
149149
case '+':
150150
return $left + $right;
151151
case '-':
@@ -176,6 +176,22 @@ public function toArray()
176176
return ['(', $this->nodes['left'], ' '.$this->attributes['operator'].' ', $this->nodes['right'], ')'];
177177
}
178178

179+
/**
180+
* @internal to be replaced by an inline strict call to in_array() in version 7.0
181+
*/
182+
public static function inArray($value, array $array): bool
183+
{
184+
if (false === $key = array_search($value, $array)) {
185+
return false;
186+
}
187+
188+
if (!\in_array($value, $array, true)) {
189+
trigger_deprecation('symfony/expression-language', '6.3', 'The "in" operator will use strict comparisons in Symfony 7.0. Loose match found with key "%s" for value %s.', $key, json_encode($value));
190+
}
191+
192+
return true;
193+
}
194+
179195
private function evaluateMatches(string $regexp, ?string $str): int
180196
{
181197
set_error_handler(function ($t, $m) use ($regexp) {

src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ public function testOperatorCollisions()
269269
$expressionLanguage = new ExpressionLanguage();
270270
$expression = 'foo.not in [bar]';
271271
$compiled = $expressionLanguage->compile($expression, ['foo', 'bar']);
272-
$this->assertSame('in_array($foo->not, [0 => $bar])', $compiled);
272+
$this->assertSame('\Symfony\Component\ExpressionLanguage\Node\BinaryNode::inArray($foo->not, [0 => $bar])', $compiled);
273273

274274
$result = $expressionLanguage->evaluate($expression, ['foo' => (object) ['not' => 'test'], 'bar' => 'test']);
275275
$this->assertTrue($result);

src/Symfony/Component/ExpressionLanguage/Tests/Node/BinaryNodeTest.php

+22-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\ExpressionLanguage\Tests\Node;
1313

14+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1 F438 415
use Symfony\Component\ExpressionLanguage\Compiler;
1516
use Symfony\Component\ExpressionLanguage\Node\ArrayNode;
1617
use Symfony\Component\ExpressionLanguage\Node\BinaryNode;
@@ -20,6 +21,8 @@
2021

2122
class BinaryNodeTest extends AbstractNodeTest
2223
{
24+
use ExpectDeprecationTrait;
25+
2326
public function getEvaluateData()
2427
{
2528
$array = new ArrayNode();
@@ -113,10 +116,10 @@ public function getCompileData()
113116
['pow(5, 2)', new BinaryNode('**', new ConstantNode(5), new ConstantNode(2))],
114117
['("a" . "b")', new BinaryNode('~', new ConstantNode('a'), new ConstantNode('b'))],
115118

116-
['in_array("a", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('a'), $array)],
117-
['in_array("c", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('c'), $array)],
118-
['!in_array("c", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('c'), $array)],
119-
['!in_array("a", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('a'), $array)],
119+
['\Symfony\Component\ExpressionLanguage\Node\BinaryNode::inArray("a", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('a'), $array)],
120+
['\Symfony\Component\ExpressionLanguage\Node\BinaryNode::inArray("c", [0 => "a", 1 => "b"])', new BinaryNode('in', new ConstantNode('c'), $array)],
121+
['!\Symfony\Component\ExpressionLanguage\Node\BinaryNode::inArray("c", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('c'), $array)],
122+
['!\Symfony\Component\ExpressionLanguage\Node\BinaryNode::inArray("a", [0 => "a", 1 => "b"])', new BinaryNode('not in', new ConstantNode('a'), $array)],
120123

121124
['range(1, 3)', new BinaryNode('..', new ConstantNode(1), new ConstantNode(3))],
122125

@@ -214,4 +217,19 @@ public function testCompileMatchesWithInvalidRegexpAsExpression()
214217
$node->compile($compiler);
215218
eval('$regexp = "this is not a regexp"; '.$compiler->getSource().';');
216219
}
220+
221+
/**
222+
* @group legacy
223+
*/
224+
public function testInOperatorStrictness()
225+
{
226+
$array = new ArrayNode();
227+
$array->addElement(new ConstantNode('a'));
228+
$array->addElement(new ConstantNode(true));
229+
230+
$node = new BinaryNode('in', new ConstantNode('b'), $array);
231+
232+
$this->expectDeprecation('Since symfony/expression-language 6.3: The "in" operator will use strict comparisons in Symfony 7.0. Loose match found with key "1" for value "b".');
233+
$this->assertTrue($node->evaluate([], []));
234+
}
217235
}

src/Symfony/Component/ExpressionLanguage/composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
],
1818
"require": {
1919
"php": ">=8.1",
20+
"symfony/deprecation-contracts": "^2.5|^3",
2021
"symfony/cache": "^5.4|^6.0",
2122
"symfony/service-contracts": "^2.5|^3"
2223
},

0 commit comments

Comments
 (0)
0