|
4 | 4 | namespace Rector\CodingStyle\Rector\FuncCall; |
5 | 5 |
|
6 | 6 | use PhpParser\Node; |
7 | | -use PhpParser\Node\Arg; |
8 | | -use PhpParser\Node\ArrayItem; |
9 | | -use PhpParser\Node\Expr; |
10 | | -use PhpParser\Node\Expr\Array_; |
11 | 7 | use PhpParser\Node\Expr\FuncCall; |
12 | | -use PhpParser\Node\Expr\Ternary; |
13 | | -use PhpParser\Node\Expr\Variable; |
14 | | -use Rector\Php\PhpVersionProvider; |
| 8 | +use Rector\Configuration\Deprecation\Contract\DeprecatedInterface; |
| 9 | +use Rector\Exception\ShouldNotHappenException; |
15 | 10 | use Rector\Rector\AbstractRector; |
16 | | -use Rector\ValueObject\PhpVersionFeature; |
17 | | -use Rector\VersionBonding\Contract\MinPhpVersionInterface; |
18 | 11 | use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample; |
19 | 12 | use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; |
20 | 13 | /** |
21 | | - * @see \Rector\Tests\CodingStyle\Rector\FuncCall\ArraySpreadInsteadOfArrayMergeRector\Php74ArraySpreadInsteadOfArrayMergeRectorTest |
22 | | - * @see \Rector\Tests\CodingStyle\Rector\FuncCall\ArraySpreadInsteadOfArrayMergeRector\Php81ArraySpreadInsteadOfArrayMergeRectorTest |
| 14 | + * @deprecated This rule is deprecated, as it is a personal preference. The spread operator makes array merges harder to read and look dangerous. |
23 | 15 | */ |
24 | | -final class ArraySpreadInsteadOfArrayMergeRector extends AbstractRector implements MinPhpVersionInterface |
| 16 | +final class ArraySpreadInsteadOfArrayMergeRector extends AbstractRector implements DeprecatedInterface |
25 | 17 | { |
26 | | - /** |
27 | | - * @readonly |
28 | | - */ |
29 | | - private PhpVersionProvider $phpVersionProvider; |
30 | | - public function __construct(PhpVersionProvider $phpVersionProvider) |
31 | | - { |
32 | | - $this->phpVersionProvider = $phpVersionProvider; |
33 | | - } |
34 | 18 | public function getRuleDefinition(): RuleDefinition |
35 | 19 | { |
36 | 20 | return new RuleDefinition('Change array_merge() to spread operator', [new CodeSample(<<<'CODE_SAMPLE' |
@@ -74,95 +58,6 @@ public function getNodeTypes(): array |
74 | 58 | */ |
75 | 59 | public function refactor(Node $node): ?Node |
76 | 60 | { |
77 | | - if ($this->isName($node, 'array_merge')) { |
78 | | - return $this->refactorArray($node); |
79 | | - } |
80 | | - return null; |
81 | | - } |
82 | | - public function provideMinPhpVersion(): int |
83 | | - { |
84 | | - return PhpVersionFeature::ARRAY_SPREAD; |
85 | | - } |
86 | | - private function refactorArray(FuncCall $funcCall): ?Array_ |
87 | | - { |
88 | | - if ($funcCall->isFirstClassCallable()) { |
89 | | - return null; |
90 | | - } |
91 | | - $array = new Array_(); |
92 | | - foreach ($funcCall->args as $arg) { |
93 | | - if (!$arg instanceof Arg) { |
94 | | - continue; |
95 | | - } |
96 | | - // cannot handle unpacked arguments |
97 | | - if ($arg->unpack) { |
98 | | - return null; |
99 | | - } |
100 | | - $value = $arg->value; |
101 | | - if ($this->shouldSkipArrayForInvalidKeys($value)) { |
102 | | - return null; |
103 | | - } |
104 | | - if ($value instanceof Array_) { |
105 | | - $array->items = array_merge($array->items, $value->items); |
106 | | - continue; |
107 | | - } |
108 | | - $value = $this->resolveValue($value); |
109 | | - $array->items[] = $this->createUnpackedArrayItem($value); |
110 | | - } |
111 | | - return $array; |
112 | | - } |
113 | | - private function shouldSkipArrayForInvalidKeys(Expr $expr): bool |
114 | | - { |
115 | | - $type = $this->getType($expr); |
116 | | - if ($type->getIterableKeyType()->isInteger()->yes()) { |
117 | | - // when on PHP 8.0+, pass non-array values already error on the first place |
118 | | - // this check avoid unpack non-array values that cause error on php 7.4 as well, |
119 | | - // @see https://3v4l.org/DuYHu#v7.4.33 |
120 | | - if (!$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::ARRAY_ON_ARRAY_MERGE)) { |
121 | | - $nativeType = $this->nodeTypeResolver->getNativeType($expr); |
122 | | - return !$nativeType->isArray()->yes(); |
123 | | - } |
124 | | - return \false; |
125 | | - } |
126 | | - // php 8.1+ allow mixed key: int, string, and null |
127 | | - return !$this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::ARRAY_SPREAD_STRING_KEYS); |
128 | | - } |
129 | | - private function resolveValue(Expr $expr): Expr |
130 | | - { |
131 | | - if ($expr instanceof FuncCall && $this->isIteratorToArrayFuncCall($expr)) { |
132 | | - /** @var Arg $arg */ |
133 | | - $arg = $expr->args[0]; |
134 | | - /** @var FuncCall $expr */ |
135 | | - $expr = $arg->value; |
136 | | - } |
137 | | - if (!$expr instanceof Ternary) { |
138 | | - return $expr; |
139 | | - } |
140 | | - if (!$expr->cond instanceof FuncCall) { |
141 | | - return $expr; |
142 | | - } |
143 | | - if (!$this->isName($expr->cond, 'is_array')) { |
144 | | - return $expr; |
145 | | - } |
146 | | - if ($expr->if instanceof Variable && $this->isIteratorToArrayFuncCall($expr->else)) { |
147 | | - return $expr->if; |
148 | | - } |
149 | | - return $expr; |
150 | | - } |
151 | | - private function createUnpackedArrayItem(Expr $expr): ArrayItem |
152 | | - { |
153 | | - return new ArrayItem($expr, null, \false, [], \true); |
154 | | - } |
155 | | - private function isIteratorToArrayFuncCall(Expr $expr): bool |
156 | | - { |
157 | | - if (!$expr instanceof FuncCall) { |
158 | | - return \false; |
159 | | - } |
160 | | - if (!$this->isName($expr, 'iterator_to_array')) { |
161 | | - return \false; |
162 | | - } |
163 | | - if ($expr->isFirstClassCallable()) { |
164 | | - return \false; |
165 | | - } |
166 | | - return isset($expr->getArgs()[0]); |
| 61 | + throw new ShouldNotHappenException(sprintf('"%s" rule is deprecated, as it is a personal preference that makes array merges harder to read', self::class)); |
167 | 62 | } |
168 | 63 | } |
0 commit comments