Skip to content

Commit

Permalink
Fix FilterVarArrayDynamicReturnTypeExtension for mixed input
Browse files Browse the repository at this point in the history
  • Loading branch information
zonuexe committed Apr 12, 2023
1 parent 9bcdc96 commit 0a39cca
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 14 deletions.
28 changes: 14 additions & 14 deletions src/Type/Php/FilterVarArrayDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
$functionName = strtolower($functionReflection->getName());
$inputArgType = $scope->getType($functionCall->getArgs()[0]->value);

$inputArrayType = $inputArgType;
$inputArrayType = $inputArgType->getArrays()[0] ?? null;
$inputConstantArrayType = null;
if ($functionName === 'filter_var_array') {
if ($inputArgType->isArray()->no()) {
Expand All @@ -72,28 +72,29 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
$inputArrayType = new ArrayType(new StringType(), new MixedType());
}

if ($inputArrayType === null) {
$inputArrayType = new ArrayType(new MixedType(), new MixedType());
if ($inputArgType->isSuperTypeOf($inputArrayType)->no()) {
return null;
}
}

$filterArgType = $scope->getType($functionCall->getArgs()[1]->value);
$filterConstantArrayType = $filterArgType->getConstantArrays()[0] ?? null;
$addEmptyType = isset($functionCall->getArgs()[2]) ? $scope->getType($functionCall->getArgs()[2]->value) : null;
$addEmpty = $addEmptyType === null || $addEmptyType->isTrue()->yes();

$valueTypesBuilder = ConstantArrayTypeBuilder::createEmpty();
$inputTypesMap = [];
$optionalKeys = [];

if ($filterArgType instanceof ConstantIntegerType) {
if ($inputConstantArrayType === null) {
$isList = $inputArrayType->isList()->yes();
$inputArrayType = $inputArrayType->getArrays()[0] ?? null;
$isList = $inputArgType->isList()->yes();
$valueType = $this->filterFunctionReturnTypeHelper->getType(
$inputArrayType === null ? new MixedType() : $inputArrayType->getItemType(),
$inputArrayType->getItemType(),
$filterArgType,
null,
);
$arrayType = new ArrayType(
$inputArrayType !== null ? $inputArrayType->getKeyType() : new MixedType(),
$valueType,
);
$arrayType = new ArrayType($inputArrayType->getKeyType(), $valueType);

return $isList ? AccessoryArrayListType::intersectWith($arrayType) : $arrayType;
}
Expand All @@ -116,11 +117,10 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
} elseif ($filterConstantArrayType === null) {
if ($inputConstantArrayType === null) {
$isList = $inputArrayType->isList()->yes();
$inputArrayType = $inputArrayType->getArrays()[0] ?? null;
$valueType = $this->filterFunctionReturnTypeHelper->getType($inputArrayType ?? new MixedType(), $filterArgType, null);
$valueType = $this->filterFunctionReturnTypeHelper->getType($inputArrayType, $filterArgType, null);

$arrayType = new ArrayType(
$inputArrayType !== null ? $inputArrayType->getKeyType() : new MixedType(),
$inputArrayType->getKeyType(),
$addEmpty ? TypeCombinator::addNull($valueType) : $valueType,
);

Expand Down Expand Up @@ -148,7 +148,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
}
} else {
$optionalKeys = $filterKeysList;
$inputTypesMap = array_fill_keys($optionalKeys, $inputArrayType->getArrays()[0]->getItemType());
$inputTypesMap = array_fill_keys($optionalKeys, $inputArrayType->getItemType());
}
}

Expand Down
46 changes: 46 additions & 0 deletions tests/PHPStan/Analyser/data/filter-var-array.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,52 @@ function constantValues(): void
], false));
}

function mixedInput(mixed $input): void
{
// filter array with add_empty=default
assertType('array{id: int|false|null}', filter_var_array($input, [
'id' => FILTER_VALIDATE_INT,
]));

// filter array with add_empty=true
assertType('array{id: int|false|null}', filter_var_array($input, [
'id' => FILTER_VALIDATE_INT,
], true));

// filter array with add_empty=false
assertType('array{id?: int|false}', filter_var_array($input, [
'id' => FILTER_VALIDATE_INT,
], false));

// filter flag with add_empty=default
assertType('array<int|false>', filter_var_array($input, FILTER_VALIDATE_INT));
// filter flag with add_empty=true
assertType('array<int|false>', filter_var_array($input, FILTER_VALIDATE_INT, true));
// filter flag with add_empty=false
assertType('array<int|false>', filter_var_array($input, FILTER_VALIDATE_INT, false));

$filter = [
'filter' => FILTER_VALIDATE_INT,
'flag' => FILTER_REQUIRE_SCALAR,
'options' => ['min_range' => 1, 'max_range' => 10],
];

// filter array with add_empty=default
assertType('array{id: int<1, 10>|false|null}', filter_var_array($input, [
'id' => $filter,
]));

// filter array with add_empty=default
assertType('array{id: int<1, 10>|false|null}', filter_var_array($input, [
'id' => $filter,
], true));

// filter array with add_empty=default
assertType('array{id?: int<1, 10>|false}', filter_var_array($input, [
'id' => $filter,
], false));
}

function emptyArrayInput(): void
{
// filter array with add_empty=default
Expand Down

0 comments on commit 0a39cca

Please sign in to comment.