-
Notifications
You must be signed in to change notification settings - Fork 11
DiAbstractServiceFactory Recursion #19
Comments
I created the following to test this: // in src/Example.php:
namespace Test;
class Example
{
}
// in test.php:
use Test\Example;
use Zend\ServiceManager\Di\ConfigProvider;
use Zend\ServiceManager\Di\DiAbstractServiceFactory;
use Zend\ServiceManager\ServiceManager;
require './vendor/autoload.php';
$container = new ServiceManager((new ConfigProvider())->getDependencyConfig());
$container->addAbstractFactory($container->get('DiAbstractServiceFactory'));
$instance = $container->get(Example::class);
var_export($instance); This mimics how zend-servicemanager-di would register its services, and demonstrates how to add its abstract factory to the container after initialization. This definitely reproduces the issue. I'm not certain how quickly we will try to address it, particularly as zend-di provides comprehensive support for zend-servicemanager as of version 3. We typically recommend using that support if you are able to to, as it provides a better path from development to production, and more flexibility in how users interact with their container. Interestingly, I checked to see if this worked in that paradigm as well: use Test\Example;
use Zend\Di\ConfigProvider;
use Zend\Di\Container\ServiceManager\AutowireFactory;
use Zend\ServiceManager\ServiceManager;
require './vendor/autoload.php';
$container = new ServiceManager(array_merge_recursive(
(new ConfigProvider())->getDependencyConfig(),
[
'abstract_factories' => [
new AutowireFactory(),
],
]
));
$instance = $container->get(Example::class);
var_export($instance); Surprisingly, the behavior is exhibited there as well. (Anecdotally, I'm surprised, as I've used the autowire factory before when prototyping functionality, and it worked fine.) I'm curious if the issue is due to having an empty constructor. Can you provide some information about the class you're trying to retrieve from the container? |
The issue exists in both cases whether the class has an empty constructor or not. Following is the class constructor /**
* Constructor
*
* \Vendor\Framework\App\ResourceConnection $resourceConnection
*/
public function __construct(
\Vendor\Framework\App\ResourceConnection $resourceConnection
) {
$this->connection = $resourceConnection->getConnection();
} A quick solution to this issue is changing /**
* Class responsible for instantiating a DiAbstractServiceFactory
*
* @param ContainerInterface $container
* @param string $name
* @param null|array $options
* @return DiAbstractServiceFactory
*/
public function __invoke(ContainerInterface $container, $name, array $options = null)
{
$factory = new DiAbstractServiceFactory($container->get('Di'), DiAbstractServiceFactory::USE_SL_NONE);
if ($container instanceof ServiceManager) {
$container->addAbstractFactory($factory, false);
}
return $factory;
} |
This repository has been closed and moved to laminas/laminas-servicemanager-di; a new issue has been opened at laminas/laminas-servicemanager-di#1. |
The
Zend\ServiceManager\Di\DiAbstractServiceFactory
when used as an abstract factory is causing recursion.The issue is caused by
Zend\ServiceManager\ServiceManager::has()
function implementation andZend\ServiceManager\Di\DiAbstractServiceFactoryFactory: :__invoke()
function which is usingDiAbstractServiceFactory::USE_SL_BEFORE_DI
andZend\ServiceManager\Di\DiServiceFactory: :get()
method which is sending the object initialization request back to theZend\ServiceManager\ServiceManager
and as a result creating the recursion.During object initialization by
ServiceManager
viaDiAbstractServiceFactory
theDiServiceFactory::get()
method checks whether it should callServiceManager
(Service Locator) first by the following code (line 126) and therefore sends the object initialization request back to theServiceManager
because both conditions for the if statement are correct in this situation.As the object initialization request is sent or pushed back to the
ServiceManager
and theServiceManager
will forward the request again toDiAbstractServiceFactory
therefore creating the recursion (sending the request back and forth) and the end result is system memory exhausted.Code to reproduce the issue
Please just use
Zend\ServiceManager\Di\DiAbstractServiceFactory
as an abstract factoryand then use
ServiceManager
to get/initialize an object. This object should not have any other factory class defined in the config. The only factory which should initialize this object should beZend\ServiceManager\Di\DiAbstractServiceFactory
.Expected results
No Recursion.
Actual results
Recursion
The text was updated successfully, but these errors were encountered: