Force singletons to be simple bindings when they have non-singleton dependencies #55497
Unanswered
thierry2015
asked this question in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
The best use case this would address is when we use Laravel Octane with request-scoped dependencies (e.g.,
\Illuminate\Contracts\Container\Container
,\Illuminate\Http\Request
,\Illuminate\Contracts\Config\Repository
, etc.). If we create a singleton with a direct reference to one of those request-scoped dependencies, we have a singleton reference to a stale/outdated object that could/will impact the garbage collection process and the reliability of the data/processes actioned through that dependency (e.g., the request carries the original request, not the current one).The scope could actually go beyond Laravel Octane, like in workers (queue, schedule)
The current DX proposed by the Laravel Octane documentation is to pass resolvers (closures, invokables) instead of the instances themselves, which would keep the parent instance as a singleton, but would require resolving the request-scoped dependencies at runtime, one by one, with explicit knowledge around their scope.
The ideal DX I think would be something similar to what NestJS does, which is to force an injectable marked as a singleton to be a simple binding when it depends on a non-singleton injectable.
I see many ways we could address this without breaking the current behaviour, as it could easily become a concern and lead to bugs that can be hard to track.
We could rely on a flag that can be made at the application bootstrap level
We could use PHP attributes around dependencies that are not marked as singleton on purpose to prevent a stale dependency from remaining in a singleton
Something additional to this to prevent wrong assumptions around singletonized dependencies would be an extra flag when configuring the application, so an error would be thrown the moment a singleton is rejected to be a simple binding (which could be something we only enable on non-production environments, or just the local environment for debugging/optimization purposes)
I see many use cases where we could still want some non-singletonized dependencies to be injected in singletons, so I think we should only treat the concrete implementations with the scoped attribute as actionable and let the other instances be injectable in singletons.
Beta Was this translation helpful? Give feedback.
All reactions