Skip to content

Commit ffea1e4

Browse files
committed
Updated Rector to commit c32b6305df1bf1a01f1a7e3d48dea5316619d505
rectorphp/rector-src@c32b630 [CodeQuality] Fill reasonable default value on OptionalParametersAfterRequiredRector (#7226)
1 parent 3fadd5b commit ffea1e4

File tree

2 files changed

+94
-29
lines changed

2 files changed

+94
-29
lines changed

rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@
1313
use PhpParser\Node\Name;
1414
use PhpParser\Node\NullableType;
1515
use PhpParser\Node\Param;
16+
use PhpParser\Node\Scalar\Float_;
17+
use PhpParser\Node\Scalar\Int_;
18+
use PhpParser\Node\Scalar\String_;
1619
use PhpParser\Node\Stmt\ClassMethod;
1720
use PhpParser\Node\Stmt\Function_;
1821
use PhpParser\Node\UnionType;
22+
use Rector\PhpParser\Node\Value\ValueResolver;
1923
use Rector\Rector\AbstractRector;
2024
use Rector\ValueObject\PhpVersionFeature;
2125
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
@@ -26,20 +30,28 @@
2630
*/
2731
final class OptionalParametersAfterRequiredRector extends AbstractRector implements MinPhpVersionInterface
2832
{
33+
/**
34+
* @readonly
35+
*/
36+
private ValueResolver $valueResolver;
37+
public function __construct(ValueResolver $valueResolver)
38+
{
39+
$this->valueResolver = $valueResolver;
40+
}
2941
public function getRuleDefinition() : RuleDefinition
3042
{
31-
return new RuleDefinition('Add null default value when a required parameter follows an optional one', [new CodeSample(<<<'CODE_SAMPLE'
43+
return new RuleDefinition('Add reasonable default value when a required parameter follows an optional one', [new CodeSample(<<<'CODE_SAMPLE'
3244
class SomeObject
3345
{
34-
public function run($optional = 1, $required)
46+
public function run($optional = 1, int $required)
3547
{
3648
}
3749
}
3850
CODE_SAMPLE
3951
, <<<'CODE_SAMPLE'
4052
class SomeObject
4153
{
42-
public function run($optional = 1, $required = null)
54+
public function run($optional = 1, int $required = 0)
4355
{
4456
}
4557
}
@@ -73,30 +85,7 @@ public function refactor(Node $node)
7385
$previousParam = $node->params[$key - 1] ?? null;
7486
if ($previousParam instanceof Param && $previousParam->default instanceof Expr) {
7587
$hasChanged = \true;
76-
$param->default = new ConstFetch(new Name('null'));
77-
if (!$param->type instanceof Node) {
78-
continue;
79-
}
80-
if ($param->type instanceof NullableType) {
81-
continue;
82-
}
83-
if ($param->type instanceof UnionType) {
84-
foreach ($param->type->types as $unionedType) {
85-
if ($unionedType instanceof Identifier && $this->isName($unionedType, 'null')) {
86-
continue 2;
87-
}
88-
}
89-
$param->type->types[] = new Identifier('null');
90-
continue;
91-
}
92-
if ($param->type instanceof IntersectionType) {
93-
$param->type = new UnionType([$param->type, new Identifier('null')]);
94-
continue;
95-
}
96-
if ($param->type instanceof ComplexType) {
97-
continue;
98-
}
99-
$param->type = new NullableType($param->type);
88+
$this->processParam($param);
10089
}
10190
}
10291
return $hasChanged ? $node : null;
@@ -105,4 +94,80 @@ public function provideMinPhpVersion() : int
10594
{
10695
return PhpVersionFeature::NULLABLE_TYPE;
10796
}
97+
/**
98+
* Look first found type reasonable value
99+
*
100+
* @param Node[] $types
101+
*/
102+
private function mapReasonableParamValue(array $types) : Expr
103+
{
104+
foreach ($types as $type) {
105+
if ($this->isName($type, 'string')) {
106+
return new String_('');
107+
}
108+
if ($this->isName($type, 'int')) {
109+
return new Int_(0);
110+
}
111+
if ($this->isName($type, 'float')) {
112+
return new Float_(0.0);
113+
}
114+
if ($this->isName($type, 'bool')) {
115+
return $this->nodeFactory->createFalse();
116+
}
117+
if ($this->isName($type, 'array')) {
118+
return $this->nodeFactory->createArray([]);
119+
}
120+
if ($this->isName($type, 'true')) {
121+
return $this->nodeFactory->createTrue();
122+
}
123+
if ($this->isName($type, 'false')) {
124+
return $this->nodeFactory->createFalse();
125+
}
126+
}
127+
return new ConstFetch(new Name('null'));
128+
}
129+
private function processParam(Param $param) : void
130+
{
131+
if (!$param->type instanceof Node) {
132+
$param->default = new ConstFetch(new Name('null'));
133+
return;
134+
}
135+
if ($param->type instanceof NullableType) {
136+
$param->default = new ConstFetch(new Name('null'));
137+
return;
138+
}
139+
if ($param->type instanceof IntersectionType) {
140+
$param->default = new ConstFetch(new Name('null'));
141+
$param->type = new UnionType([$param->type, new Identifier('null')]);
142+
return;
143+
}
144+
if ($param->type instanceof UnionType) {
145+
foreach ($param->type->types as $unionedType) {
146+
if ($unionedType instanceof Identifier && $this->isName($unionedType, 'null')) {
147+
$param->default = new ConstFetch(new Name('null'));
148+
return;
149+
}
150+
}
151+
$reasonableValue = $this->mapReasonableParamValue($param->type->types);
152+
if ($this->valueResolver->isNull($reasonableValue)) {
153+
$param->default = new ConstFetch(new Name('null'));
154+
$param->type->types[] = new Identifier('null');
155+
return;
156+
}
157+
$param->default = $reasonableValue;
158+
return;
159+
}
160+
if ($param->type instanceof ComplexType) {
161+
return;
162+
}
163+
$reasonableValue = $this->mapReasonableParamValue([$param->type]);
164+
if ($this->valueResolver->isNull($reasonableValue)) {
165+
if (!$param->type instanceof Identifier || !$this->isNames($param->type, ['null', 'mixed'])) {
166+
$param->type = new NullableType($param->type);
167+
}
168+
$param->default = new ConstFetch(new Name('null'));
169+
return;
170+
}
171+
$param->default = $reasonableValue;
172+
}
108173
}

src/Application/VersionResolver.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ final class VersionResolver
1919
* @api
2020
* @var string
2121
*/
22-
public const PACKAGE_VERSION = 'f414fd200285c0cd3eac73ba1a9604a84b2bc1a6';
22+
public const PACKAGE_VERSION = 'c32b6305df1bf1a01f1a7e3d48dea5316619d505';
2323
/**
2424
* @api
2525
* @var string
2626
*/
27-
public const RELEASE_DATE = '2025-09-07 00:38:24';
27+
public const RELEASE_DATE = '2025-09-07 07:39:44';
2828
/**
2929
* @var int
3030
*/

0 commit comments

Comments
 (0)