Faster Rector on 0.15.22

This feature is available since Rector 0.15.22.

Correctness has more priority than speed. Since version 0.14.x, Rector has better scope refresh handling for multiple rules and handle more crash that happen on 0.13.x. On 0.15.x, Rector give optimization a chance to raise.

This performance optimization is contributed by keulinho, which with his knowledge on usage of blackfire, provided various PRs on performance optimizations:

What happened?

  1. Memoization resolved data

On various use cases, data can be hit in multiple rules, again and again, that's worth cached, for example:

     /**
     * @var array<string, bool>
     */
    private array $skippedFiles = [];

    public function shouldSkip(string | object $element, string $filePath): bool
    {
        if (isset($this->skippedFiles[$filePath])) {
            return $this->skippedFiles[$filePath];
        }

        $skippedPaths = $this->skippedPathsResolver->resolve();
        return $this->skippedFiles[$filePath] = $this->fileInfoMatcher->doesFileInfoMatchPatterns($filePath, $skippedPaths);
    }

Above save data with index $filePath to a property, which the service is shared so it won't hit again.

  1. Avoid object creation when not needed, for example:

Before

if (! $this->isObjectType($methodCall->var, new ObjectType('ReflectionFunctionAbstract'))) {
    return false;
}

return $this->isName($methodCall->name, 'getReturnType');

After

if (! $this->isName($methodCall->name, 'getReturnType')) {
    return false;
}

return $this->isObjectType($methodCall->var, new ObjectType('ReflectionFunctionAbstract'));

Above, no need to create new ObjectType() when the name is not getReturnType, which faster.

In the CodeIgniter 4 project, it already show twice faster:

Before

After

Another future improvements effort

  1. Moving away from parent lookup after node found by NodeFinder to SimpleCallableNodeTraverser, like this this PR:

Above:

✔️ We know that we search specific Node, which is Assign node with local property ✔️ No need to traverse deep when we found anonymous class ( new class ) and inner function inside ClassMethod

  1. Replacing lookup all nodes to only found first node, like this PR:

Above:

✔️ Instead of get all nodes by instance, and search name later, we find first found instance and directly verify the name.



Start feel the speed. Run composer update!


Happy coding!