Skip to content

[DependencyInjection] ContainerBuilder::getReflectionClass() does not support interfaces, if symfony/config package not present #58821

Closed
@donquixote

Description

@donquixote

Symfony version(s) affected

7.2.0

Description

The ContainerBuilder::getReflectionClass() method does not support interfaces when 'symfony/config' package not present.

Given an interface MyInterface..
With symfony/config package present, $builder->getReflectionClass(MyInterface::class) will return a \ReflectionClass object for that interface.
With symfony/config package missing, $builder->getReflectionClass(MyInterface::class) will return false.

This has an impact on AutowirePass, if the class on a service definition is an interface.

How to reproduce

This problem manifests in two levels.

Low-level manifestation

<?php

use Symfony\Component\DependencyInjection\ContainerBuilder;

require_once __DIR__ . '/vendor/autoload.php';

interface I {}

$rc = (new ContainerBuilder())->getReflectionClass(I::class);

// With symfony/config: ReflectionClass.
// Without symfony/config: NULL
print get_debug_type($rc) . "\n";

Higher level manifestation in autowire

<?php

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

require_once __DIR__ . '/vendor/autoload.php';

class Dependency {}
interface ServiceInterface {}
class Service implements ServiceInterface {}
class Factories {
  public static function createService(
    Dependency $dependency,
  ): ServiceInterface {
    return new Service();
  }
}

$builder = new ContainerBuilder();

$definition = new Definition(Dependency::class);
$builder->setDefinition(Dependency::class, $definition);

$definition = new Definition(ServiceInterface::class);
$definition->setAutowired(true);
$definition->setFactory([Factories::class, 'createService']);
$definition->setPublic(true);
$builder->setDefinition('service', $definition);

$builder->compile();

$service = $builder->get('service');

print get_debug_type($service) . "\n";

Possible Solution

In ContainerBuilder::getReflectionClass(), add a || interface_exists($class)`.

        try {
            if (isset($this->classReflectors[$class])) {
                $classReflector = $this->classReflectors[$class];
            } elseif (false && class_exists(ClassExistenceResource::class)) {
                $resource = new ClassExistenceResource($class, false);
                $classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
            } else {
                $classReflector = (class_exists($class) || interface_exists($class)) ? new \ReflectionClass($class) : false;
            }
        } catch (\ReflectionException $e) {
            if ($throw) {
                throw $e;
            }
        }

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions