parsedNodesByType = $parsedNodesByType; } public function getDefinition(): RectorDefinition { return new RectorDefinition('Convert [$this, "method"] to proper anonymous function', [ new CodeSample( <<<'CODE_SAMPLE' class SomeClass { public function run() { $values = [1, 5, 3]; usort($values, [$this, 'compareSize']); return $values; } private function compareSize($first, $second) { return $first <=> $second; } } CODE_SAMPLE , <<<'CODE_SAMPLE' class SomeClass { public function run() { $values = [1, 5, 3]; usort($values, function ($first, $second) { return $this->compareSize($first, $second); }); return $values; } private function compareSize($first, $second) { return $first <=> $second; } } CODE_SAMPLE ), ]); } /** * @return string[] */ public function getNodeTypes(): array { return [Array_::class]; } /** * @param Array_ $node */ public function refactor(Node $node): ?Node { if (count($node->items) !== 2) { return null; } // is callable? // can be totally empty, e.g [, $value] if ($node->items[0] === null) { return null; } $objectVariable = $node->items[0]->value; $classMethod = $this->matchCallableMethod($objectVariable, $node->items[1]->value); if ($classMethod === null) { return null; } $anonymousFunction = new Closure(); $anonymousFunction->params = $classMethod->params; $innerMethodCall = new MethodCall($objectVariable, $classMethod->name); $innerMethodCall->args = $this->convertParamsToArgs($classMethod->params); if ($classMethod->returnType !== null) { $anonymousFunction->returnType = $classMethod->returnType; } $anonymousFunction->stmts[] = new Return_($innerMethodCall); if ($objectVariable instanceof Variable) { if (! $this->isName($objectVariable, 'this')) { $anonymousFunction->uses[] = new ClosureUse($objectVariable); } } return $anonymousFunction; } /** * @param Param[] $params * @return Arg[] */ private function convertParamsToArgs(array $params): array { $args = []; foreach ($params as $key => $param) { $args[$key] = new Arg($param->var); } return $args; } private function matchCallableMethod(Expr $objectExpr, Expr $methodExpr): ?ClassMethod { $methodName = $this->getValue($methodExpr); foreach ($this->getTypes($objectExpr) as $type) { $class = $this->parsedNodesByType->findClass($type); if ($class === null) { continue; } $classMethod = $class->getMethod($methodName); if ($classMethod === null) { continue; } if ($this->isName($objectExpr, 'this')) { return $classMethod; } if ($classMethod->isPublic()) { return $classMethod; } return null; } return null; } }