Skip to content

Commit 3f716d4

Browse files
authored
Fix filter_var throw-on-failure detection (phpstan#6042)
1 parent f8e7061 commit 3f716d4

3 files changed

Lines changed: 39 additions & 22 deletions

File tree

src/Type/Php/FilterVarThrowTypeExtension.php

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
use PHPStan\Php\PhpVersion;
1010
use PHPStan\Reflection\FunctionReflection;
1111
use PHPStan\Reflection\ReflectionProvider;
12-
use PHPStan\Type\Constant\ConstantIntegerType;
13-
use PHPStan\Type\Constant\ConstantStringType;
1412
use PHPStan\Type\DynamicFunctionThrowTypeExtension;
1513
use PHPStan\Type\ObjectType;
1614
use PHPStan\Type\Type;
@@ -22,6 +20,7 @@ final class FilterVarThrowTypeExtension implements DynamicFunctionThrowTypeExten
2220
public function __construct(
2321
private ReflectionProvider $reflectionProvider,
2422
private PhpVersion $phpVersion,
23+
private FilterFunctionReturnTypeHelper $filterFunctionReturnTypeHelper,
2524
)
2625
{
2726
}
@@ -39,7 +38,7 @@ public function getThrowTypeFromFunctionCall(
3938
Scope $scope,
4039
): ?Type
4140
{
42-
if (!isset($funcCall->getArgs()[3])) {
41+
if (!isset($funcCall->getArgs()[2])) {
4342
return null;
4443
}
4544

@@ -50,31 +49,14 @@ public function getThrowTypeFromFunctionCall(
5049
return null;
5150
}
5251

53-
$flagsExpr = $funcCall->getArgs()[3]->value;
52+
$flagsExpr = $funcCall->getArgs()[2]->value;
5453
$flagsType = $scope->getType($flagsExpr);
5554

56-
if ($flagsType->isConstantArray()->yes()) {
57-
$flagsType = $flagsType->getOffsetValueType(new ConstantStringType('flags'));
58-
}
59-
60-
$flag = $this->getConstant();
61-
62-
if ($flag !== null && $flagsType instanceof ConstantIntegerType && ($flagsType->getValue() & $flag) === $flag) {
55+
if (!$this->filterFunctionReturnTypeHelper->hasFlag('FILTER_THROW_ON_FAILURE', $flagsType)->no()) {
6356
return new ObjectType('Filter\FilterFailedException');
6457
}
6558

6659
return null;
6760
}
6861

69-
private function getConstant(): ?int
70-
{
71-
$constant = $this->reflectionProvider->getConstant(new Name('FILTER_THROW_ON_FAILURE'), null);
72-
$valueType = $constant->getValueType();
73-
if (!$valueType instanceof ConstantIntegerType) {
74-
return null;
75-
}
76-
77-
return $valueType->getValue();
78-
}
79-
8062
}

tests/PHPStan/Rules/Exceptions/CatchWithUnthrownExceptionRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ public function testBug4863(): void
299299
$this->analyse([__DIR__ . '/data/bug-4863.php'], []);
300300
}
301301

302+
#[RequiresPhp('>= 8.5.0')]
303+
public function testFilterVarThrowOnFailure(): void
304+
{
305+
$this->analyse([__DIR__ . '/data/filter-var-throw-on-failure.php'], []);
306+
}
307+
302308
#[RequiresPhp('>= 8.0.0')]
303309
public function testBug5866(): void
304310
{
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php // lint >= 8.5
2+
3+
declare(strict_types = 1);
4+
5+
namespace FilterVarThrowOnFailure;
6+
7+
function validateMac(mixed $value): void
8+
{
9+
try {
10+
filter_var($value, FILTER_VALIDATE_MAC, FILTER_THROW_ON_FAILURE);
11+
} catch (\Filter\FilterFailedException) {
12+
}
13+
}
14+
15+
function validateMacWithFlagsArray(mixed $value): void
16+
{
17+
try {
18+
filter_var($value, FILTER_VALIDATE_MAC, ['flags' => FILTER_THROW_ON_FAILURE]);
19+
} catch (\Filter\FilterFailedException) {
20+
}
21+
}
22+
23+
function validateInt(mixed $value): void
24+
{
25+
try {
26+
filter_var($value, FILTER_VALIDATE_INT, FILTER_THROW_ON_FAILURE);
27+
} catch (\Filter\FilterFailedException) {
28+
}
29+
}

0 commit comments

Comments
 (0)