Repository: symfony/symfony
File: src/Symfony/Component/ObjectMapper/Metadata/ReverseClassObjectMapperMetadataFactory.php (PHP)

Code before:
 */
final class ReverseClassObjectMapperMetadataFactory implements ObjectMapperMetadataFactoryInterface
{
    private array $attributesCache = [];

    public function __construct(
        private readonly ObjectMapperMetadataFactoryInterface $objectMapperMetadataFactory,
        private readonly array $classMap,
    ) {
    }

    public function create(object $object, ?string $property = null, array $context = []): array
    {
        $key = $object::class.($property ?? '');

        if (isset($this->attributesCache[$key])) {
            return $this->attributesCache[$key];
        }

        $mappings = $this->objectMapperMetadataFactory->create($object, $property, $context);

        if (null === $property && isset($this->classMap[$object::class])) {
            $mappings[] = new Mapping($this->classMap[$object::class], $object::class);
        }

        return $this->attributesCache[$key] = $mappings;
    }
}


Review comment (performance):
```suggestion
		if (null !== $property) {
		    return $this->objectMapperMetadataFactory->create($object, $property, $context);
		}
		
		$class = $object::class;
		if (isset($this->attributesCache[$class])) {
		    return $this->attributesCache[$class];
		}
		
		$mappings = $this->objectMapperMetadataFactory->create($object, null, $context);
		
		if (isset($this->classMap[$class])) {
		    $mappings[] = new Mapping($this->classMap[$class], $class);
		}
		
		return $this->attributesCache[$class] = $mappings;
```

Code after:
 *
 * @author Florent Blaison <florent.blaison@gmail.com>
 */
final class ReverseClassObjectMapperMetadataFactory implements ObjectMapperMetadataFactoryInterface
{
    /**
     * @var array<string, list<Mapping>>
     */
    private array $attributesCache = [];

    /**
     * @param array<class-string, class-string> $classMap
     */
    public function __construct(
        private readonly ObjectMapperMetadataFactoryInterface $objectMapperMetadataFactory,
        private readonly array $classMap,
    ) {
    }

    public function create(object $object, ?string $property = null, array $context = []): array
    {
        $class = $object::class;
        $key = $class.($property ? '.'.$property : '');

        if (isset($this->attributesCache[$key])) {
            return $this->attributesCache[$key];
        }

        $mappings = $this->objectMapperMetadataFactory->create($object, $property, $context);

        if (!$targetClass = $this->classMap[$class] ?? null) {
            return $mappings;
        }

        if (!$property) {
            $mappings[] = new Mapping($targetClass);

            return $this->attributesCache[$key] = $mappings;
        }

        $refl = new \ReflectionClass($targetClass);
        foreach ($refl->getProperties() as $reflProperty) {
            $attributes = $reflProperty->getAttributes(Map::class, \ReflectionAttribute::IS_INSTANCEOF);

            foreach ($attributes as $attribute) {
                $map = $attribute->newInstance();
                // We're forcing the target on a reverse mapping to the property name, doesn't make sense without a source
                if ($map->source) {
                    $mappings[] = new Mapping($reflProperty->getName(), $map->source, $map->if, $map->transform);
                }
            }