Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4da16b3

Browse files
rvanvelzenondrejmirtes
authored andcommitted
Fix array_walk callback parameters
1 parent 135f4c1 commit 4da16b3

5 files changed

Lines changed: 72 additions & 21 deletions

File tree

conf/config.neon

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,11 @@ services:
377377
tags:
378378
- phpstan.parser.richParserNodeVisitor
379379

380+
-
381+
class: PHPStan\Parser\ArrayWalkArgVisitor
382+
tags:
383+
- phpstan.parser.richParserNodeVisitor
384+
380385
-
381386
class: PHPStan\Parser\NewAssignedToPropertyVisitor
382387
tags:

src/Parser/ArrayWalkArgVisitor.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Parser;
4+
5+
use PhpParser\Node;
6+
use PhpParser\NodeVisitorAbstract;
7+
8+
class ArrayWalkArgVisitor extends NodeVisitorAbstract
9+
{
10+
11+
public function enterNode(Node $node): ?Node
12+
{
13+
if ($node instanceof Node\Expr\FuncCall && $node->name instanceof Node\Name) {
14+
$functionName = $node->name->toLowerString();
15+
if ($functionName === 'array_walk') {
16+
$args = $node->getArgs();
17+
if (isset($args[0])) {
18+
$args[0]->setAttribute('isArrayWalkArg', true);
19+
}
20+
}
21+
}
22+
return null;
23+
}
24+
25+
}

src/Reflection/ParametersAcceptorSelector.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,36 @@ public static function selectFromArgs(
142142
),
143143
];
144144
}
145+
146+
if (isset($args[0]) && (bool) $args[0]->getAttribute('isArrayWalkArg')) {
147+
$arrayWalkParameters = [
148+
new DummyParameter('item', self::getIterableValueType($scope->getType($args[0]->value)), false, PassedByReference::createReadsArgument(), false, null),
149+
new DummyParameter('key', self::getIterableKeyType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
150+
];
151+
if (isset($args[2])) {
152+
$arrayWalkParameters[] = new DummyParameter('arg', $scope->getType($args[2]->value), false, PassedByReference::createNo(), false, null);
153+
}
154+
155+
$acceptor = $parametersAcceptors[0];
156+
$parameters = $acceptor->getParameters();
157+
$parameters[1] = new NativeParameterReflection(
158+
$parameters[1]->getName(),
159+
$parameters[1]->isOptional(),
160+
new CallableType($arrayWalkParameters, new MixedType(), false),
161+
$parameters[1]->passedByReference(),
162+
$parameters[1]->isVariadic(),
163+
$parameters[1]->getDefaultValue(),
164+
);
165+
$parametersAcceptors = [
166+
new FunctionVariant(
167+
$acceptor->getTemplateTypeMap(),
168+
$acceptor->getResolvedTemplateTypeMap(),
169+
$parameters,
170+
$acceptor->isVariadic(),
171+
$acceptor->getReturnType(),
172+
),
173+
];
174+
}
145175
}
146176

147177
if (count($parametersAcceptors) === 1) {

stubs/arrayFunctions.stub

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,6 @@ function array_reduce(
1616
$three = null
1717
) {}
1818

19-
/**
20-
* @template TKey of array-key
21-
* @template TValue of mixed
22-
* @template TUser of mixed
23-
*
24-
* @param array<TKey, TValue> $one
25-
* @param callable(TValue, TKey, TUser=): mixed $two
26-
* @param TUser $three
27-
*
28-
* @return true
29-
*/
30-
function array_walk(
31-
array &$one,
32-
callable $two,
33-
$three = null
34-
): bool {}
35-
3619
/**
3720
* @template T of mixed
3821
*

tests/PHPStan/Rules/Functions/CallToFunctionParametersRuleTest.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -587,27 +587,35 @@ public function testArrayWalkCallback(): void
587587
{
588588
$this->analyse([__DIR__ . '/data/array_walk.php'], [
589589
[
590-
'Parameter #2 $callback of function array_walk expects callable(int, string, mixed): mixed, Closure(stdClass, float): \'\' given.',
590+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\'): mixed, Closure(stdClass, float): \'\' given.',
591591
6,
592592
],
593593
[
594-
'Parameter #2 $callback of function array_walk expects callable(int, string, string): mixed, Closure(int, string, int): \'\' given.',
594+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\', \'extra\'): mixed, Closure(int, string, int): \'\' given.',
595595
14,
596596
],
597+
[
598+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\'): mixed, Closure(int, string, int): \'\' given.',
599+
23,
600+
],
597601
]);
598602
}
599603

600604
public function testArrayWalkArrowFunctionCallback(): void
601605
{
602606
$this->analyse([__DIR__ . '/data/array_walk_arrow.php'], [
603607
[
604-
'Parameter #2 $callback of function array_walk expects callable(int, string, mixed): mixed, Closure(stdClass, float): \'\' given.',
608+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\'): mixed, Closure(stdClass, float): \'\' given.',
605609
6,
606610
],
607611
[
608-
'Parameter #2 $callback of function array_walk expects callable(int, string, string): mixed, Closure(int, string, int): \'\' given.',
612+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\', \'extra\'): mixed, Closure(int, string, int): \'\' given.',
609613
12,
610614
],
615+
[
616+
'Parameter #2 $callback of function array_walk expects callable(1|2, \'bar\'|\'foo\'): mixed, Closure(int, string, int): \'\' given.',
617+
19,
618+
],
611619
]);
612620
}
613621

0 commit comments

Comments
 (0)