Although creating an object in the container using new with an empty constructor is a good practice, eventually, you can outsource the creation of all necessary dependencies to a separate method in a special class and register its execution in the container. However, there are ways to resolve dependencies without resorting to creating a separate wrapper class.
If it becomes necessary to reuse a service from the container to initialize another service in the container, we turn to the capabilities provided by dependency injection. In the class App\Bootstrap\ContainerFactory, these methods are available, as they are in a special class for creating the container.
For example, it is necessary to initialize the constructor of a service in the container. To do this, in the body of the match operator of the App\Bootstrap\ContainerFactory class, you need to add approximately the following match:
Now in the constructor of the DemoService class, the current ExampleService will be injected as defined in the container. All dependencies not explicitly specified in the used example will be resolved automatically (variant 2).
It is important to ensure that dependencies do not form a cyclic dependency, which can occur if the object in the container makes another request to the container for the initialization of itself.
A more complex example:
In this way, in the framework's container, despite its seeming simplicity, you can add various interdependent services.
By default, the framework does not allow adding services after the container has been initialized. However, by overriding the getSingleton() method to be public in the ContainerFactory class, you gain the ability to add objects to the container in your user code through this static method. Here’s an example of modifying the class:
From the example, it is clear that support for lazy initialization through the callable type and its handler has also been added.