66
77use PhpParser \Node ;
88use PhpParser \Node \Expr \ArrayDimFetch ;
9+ use PhpParser \Node \Expr \BinaryOp \Minus ;
910use PhpParser \Node \Expr \FuncCall ;
11+ use PhpParser \Node \Scalar \Int_ ;
1012use Rector \NodeTypeResolver \Node \AttributeKey ;
1113use Rector \PHPStan \ScopeFetcher ;
1214use Rector \Rector \AbstractRector ;
@@ -40,11 +42,15 @@ public function getRuleDefinition(): RuleDefinition
4042 <<<'CODE_SAMPLE'
4143echo $array[array_key_first($array)];
4244echo $array[array_key_last($array)];
45+ echo array_values($array)[0];
46+ echo array_values($array)[count($array) - 1];
4347CODE_SAMPLE
4448 ,
4549 <<<'CODE_SAMPLE'
4650echo array_first($array);
4751echo array_last($array);
52+ echo array_first($array);
53+ echo array_last($array);
4854CODE_SAMPLE
4955 ),
5056 ]
@@ -63,6 +69,24 @@ public function getNodeTypes(): array
6369 * @param ArrayDimFetch $node
6470 */
6571 public function refactor (Node $ node ): ?FuncCall
72+ {
73+ if ($ node ->dim instanceof FuncCall) {
74+ return $ this ->refactorArrayKeyPattern ($ node );
75+ }
76+
77+ if ($ node ->var instanceof FuncCall && ($ node ->dim instanceof Int_ || $ node ->dim instanceof Minus)) {
78+ return $ this ->refactorArrayValuesPattern ($ node );
79+ }
80+
81+ return null ;
82+ }
83+
84+ public function provideMinPhpVersion (): int
85+ {
86+ return PhpVersionFeature::ARRAY_FIRST_LAST ;
87+ }
88+
89+ private function refactorArrayKeyPattern (ArrayDimFetch $ node ): ?FuncCall
6690 {
6791 if (! $ node ->dim instanceof FuncCall) {
6892 return null ;
@@ -100,8 +124,68 @@ public function refactor(Node $node): ?FuncCall
100124 return $ this ->nodeFactory ->createFuncCall ($ functionName , [$ node ->var ]);
101125 }
102126
103- public function provideMinPhpVersion ( ): int
127+ private function refactorArrayValuesPattern ( ArrayDimFetch $ node ): ? FuncCall
104128 {
105- return PhpVersionFeature::ARRAY_FIRST_LAST ;
129+ if (! $ node ->var instanceof FuncCall) {
130+ return null ;
131+ }
132+
133+ if (! $ this ->isName ($ node ->var , 'array_values ' )) {
134+ return null ;
135+ }
136+
137+ if ($ node ->var ->isFirstClassCallable ()) {
138+ return null ;
139+ }
140+
141+ if (count ($ node ->var ->getArgs ()) !== 1 ) {
142+ return null ;
143+ }
144+
145+ $ scope = ScopeFetcher::fetch ($ node );
146+ if ($ scope ->isInExpressionAssign ($ node )) {
147+ return null ;
148+ }
149+
150+ if ($ node ->getAttribute (AttributeKey::IS_UNSET_VAR )) {
151+ return null ;
152+ }
153+
154+ $ arrayArg = $ node ->var ->getArgs ()[0 ]
155+ ->value ;
156+
157+ if ($ node ->dim instanceof Int_ && $ node ->dim ->value === 0 ) {
158+ return $ this ->nodeFactory ->createFuncCall ('array_first ' , [$ arrayArg ]);
159+ }
160+
161+ if ($ node ->dim instanceof Minus) {
162+ if (! $ node ->dim ->left instanceof FuncCall) {
163+ return null ;
164+ }
165+
166+ if (! $ this ->isName ($ node ->dim ->left , 'count ' )) {
167+ return null ;
168+ }
169+
170+ if ($ node ->dim ->left ->isFirstClassCallable ()) {
171+ return null ;
172+ }
173+
174+ if (count ($ node ->dim ->left ->getArgs ()) !== 1 ) {
175+ return null ;
176+ }
177+
178+ if (! $ node ->dim ->right instanceof Int_ || $ node ->dim ->right ->value !== 1 ) {
179+ return null ;
180+ }
181+
182+ if (! $ this ->nodeComparator ->areNodesEqual ($ arrayArg , $ node ->dim ->left ->getArgs ()[0 ]->value )) {
183+ return null ;
184+ }
185+
186+ return $ this ->nodeFactory ->createFuncCall ('array_last ' , [$ arrayArg ]);
187+ }
188+
189+ return null ;
106190 }
107191}
0 commit comments