Skip to content

Lack of infinite recursion detection for abstract factories #218

@boesing

Description

@boesing

Bug Report

Q A
Version(s) 3.22.1, 4.0.0*

Summary

There is a lack of infinite recursion detection for both get and has when it comes to abstract factories.

Ref: laminas/laminas-cache#284

Current behavior

When checking a service via has in factories (one abstract factory has to be involved) or receiving a service via get, an infinite recursion along with an application crash is the result.

  1. $container->has('foo');
  2. SM checks all services, aliases and factories for foo
  3. foo not found in services, aliases or factories
  4. SM checks all abstract factories for foo
  5. First abstract factory which checks for $container->has('foo'); will start over No. 1

How to reproduce

use Laminas\ServiceManager\Factory\AbstractFactoryInterface;
use Psr\Container\ContainerInterface;

final class GenericAbstractFactory implements AbstractFactoryInterface
{
    public function canCreate(ContainerInterface $container, $requestedName)
    {
         if (!$container->has('foo')) {
             return false;
         }
        
          $foo = $container->get('foo');
          // check foo for whatever
          return true; // or false, depending on what $foo represents
    }

    public function __invoke(ContainerInterface $container, $requestedName, ?array $options = null)
    {
         $foo = $container->get('foo'); // we can safely assume that `foo` exists since we checked that in `canCreate` alrady
         // do whatever with foo
         return stdClass(); // return service, maybe with data from foo
    }
}

final class GenericFactory
{
     public function __invoke(ContainerInterface $container): object
     {
          if (!$container->has('foo')) {
              return new stdClass();
          }

          $foo = $container->get('foo');
          // do whatever with foo
          return new stdClass();     
     }
}

$container = new ServiceManager([
     'abstract_factories' => [
         GenericAbstractFactory::class,
      ],
     'factories' => [
         stdClass::class => GenericFactory::class,
     ],
]);

$object = $container->get(stdClass::class); // infinite loop occurs
// unreachable line

Expected behavior

Infinite recursions are prevented from abstract factories.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions