Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 460df80

Browse files
Prevent accurate comparison of floating-point numbers
1 parent 18c0b6e commit 460df80

File tree

3 files changed

+108
-0
lines changed

3 files changed

+108
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPStan\Rules\Operators;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Expr\BinaryOp;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Type\FloatType;
12+
13+
class OperandsInComparisonRule implements Rule
14+
{
15+
/**
16+
* @return string
17+
*/
18+
public function getNodeType(): string
19+
{
20+
return BinaryOp::class;
21+
}
22+
23+
/**
24+
* @param Node $node
25+
* @param Scope $scope
26+
* @return array
27+
*/
28+
public function processNode(Node $node, Scope $scope): array
29+
{
30+
if (!$node instanceof BinaryOp\Equal
31+
&& !$node instanceof BinaryOp\Identical
32+
&& !$node instanceof BinaryOp\GreaterOrEqual
33+
&& !$node instanceof BinaryOp\SmallerOrEqual
34+
) {
35+
return [];
36+
}
37+
38+
$rightType = $scope->getType($node->right);
39+
$leftType = $scope->getType($node->left);
40+
41+
if ($rightType instanceof FloatType || $leftType instanceof FloatType) {
42+
if ($node instanceof BinaryOp\Equal || $node instanceof BinaryOp\Identical) {
43+
return [
44+
'You can not use an exact comparison for floating-point numbers.
45+
Should use `abs($left - $right) < $epsilon`, where $epsilon maximum permissible error.',
46+
];
47+
}
48+
if ($node instanceof BinaryOp\GreaterOrEqual) {
49+
return [
50+
'You can not use an exact comparison for floating-point numbers.
51+
Should use `$left - $right >= $epsilon`, where $epsilon maximum permissible error.'
52+
];
53+
}
54+
if ($node instanceof BinaryOp\SmallerOrEqual) {
55+
return [
56+
'You can not use an exact comparison for floating-point numbers.
57+
Should use `$right - $left >= $epsilon`, where $epsilon maximum permissible error.'
58+
];
59+
}
60+
}
61+
}
62+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPStan\Rules\Operators;
6+
7+
use PHPStan\Rules\Rule;
8+
9+
class OperandsInComparisonRuleTest extends \PHPStan\Testing\RuleTestCase
10+
{
11+
protected function getRule(): Rule
12+
{
13+
return new OperandsInComparisonRule();
14+
}
15+
16+
public function testRule(): void
17+
{
18+
$this->analyse([__DIR__ . '/data/operators.php'], [
19+
[
20+
'You can not use an exact comparison for floating-point numbers.
21+
Should use `abs($left - $right) < $epsilon`, where $epsilon maximum permissible error.',
22+
113,
23+
],
24+
[
25+
'You can not use an exact comparison for floating-point numbers.
26+
Should use `abs($left - $right) < $epsilon`, where $epsilon maximum permissible error.',
27+
114,
28+
],
29+
[
30+
'You can not use an exact comparison for floating-point numbers.
31+
Should use `$left - $right >= $epsilon`, where $epsilon maximum permissible error.',
32+
115,
33+
],
34+
[
35+
'You can not use an exact comparison for floating-point numbers.
36+
Should use `$right - $left >= $epsilon`, where $epsilon maximum permissible error.',
37+
116,
38+
],
39+
]);
40+
}
41+
}

‎tests/Rules/Operators/data/operators.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,8 @@ function (array $array, int $int, $mixed) {
109109

110110
explode($mixed, $mixed) + $int;
111111
};
112+
113+
$float === 123.2;
114+
$float == 123.2;
115+
$float >= 123.2;
116+
$float <= 123.2;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /