Repository: symfony/symfony
File: src/Symfony/Component/TypeInfo/TypeContext/TypeContextFactory.php (PHP)

Code before:
use PHPStan\PhpDocParser\ParserConfig;
use Symfony\Component\TypeInfo\Exception\LogicException;
use Symfony\Component\TypeInfo\Exception\RuntimeException;
use Symfony\Component\TypeInfo\Exception\UnsupportedException;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\Type\ObjectType;
use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver;

/**
 * Creates a type resolving context.
 *
 * @author Mathias Arlaud <mathias.arlaud@gmail.com>
 * @author Baptiste Leduc <baptiste.leduc@gmail.com>
 * @author Pierre-Yves Landuré <landure@gmail.com>
 */
final class TypeContextFactory
{
    /**
     * @var array<class-string, \ReflectionClass>
     */
    private static array $reflectionClassCache = [];

    /**
     * @var array<string,array<string,TypeContext>
     */
    private static array $intermediateTypeContextCache = [];

    /**
     * @var array<string,array<string,TypeContext>
     */
    private array $typeContextCache = [];

    private ?Lexer $phpstanLexer = null;
    private ?PhpDocParser $phpstanParser = null;

    public function __construct(
        private readonly ?StringTypeResolver $stringTypeResolver = null,
    ) {
    }

    public function createFromClassName(string $calledClassName, ?string $declaringClassName = null): TypeContext
    {
        $declaringClassName ??= $calledClassName;

        $this->typeContextCache[$declaringClassName][$calledClassName] ??= $this->createNewInstanceFromClassName(
            $calledClassName,
            $declaringClassName,
        );

        return $this->typeContextCache[$declaringClassName][$calledClassName];
    }

Review comment (performance):
Please don't make the cache static. We don't need that global state (thus, this global state would be flawed if we have different string type resolvers in 2 instances of the factory).

Code after:
use PHPStan\PhpDocParser\ParserConfig;
use Symfony\Component\TypeInfo\Exception\LogicException;
use Symfony\Component\TypeInfo\Exception\RuntimeException;
use Symfony\Component\TypeInfo\Exception\UnsupportedException;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\Type\ObjectType;
use Symfony\Component\TypeInfo\TypeResolver\StringTypeResolver;

/**
 * Creates a type resolving context.
 *
 * @author Mathias Arlaud <mathias.arlaud@gmail.com>
 * @author Baptiste Leduc <baptiste.leduc@gmail.com>
 * @author Pierre-Yves Landuré <landure@gmail.com>
 */
final class TypeContextFactory
{
    /**
     * @var array<class-string, \ReflectionClass>
     */
    private static array $reflectionClassCache = [];

    /**
     * @var array<string,array<string,TypeContext>
     */
    private array $intermediateTypeContextCache = [];

    /**
     * @var array<string,array<string,TypeContext>
     */
    private array $typeContextCache = [];

    private ?Lexer $phpstanLexer = null;
    private ?PhpDocParser $phpstanParser = null;

    /**
     * @param array<string, string> $extraTypeAliases
     */
    public function __construct(
        private readonly ?StringTypeResolver $stringTypeResolver = null,
        private readonly array $extraTypeAliases = [],
    ) {
    }

    public function createFromClassName(string $calledClassName, ?string $declaringClassName = null): TypeContext
    {
        $declaringClassName ??= $calledClassName;

        return $this->typeContextCache[$declaringClassName][$calledClassName] ??= $this->createNewInstanceFromClassName($calledClassName, $declaringClassName);
    }