[Discussion] Reflection-based constructor autowiring (scope clarification)
| From: | ANDRÁS Zoltán Gyárfás | Date: | Sun, 28 Dec 2025 09:39:44 +0000 |
| Subject: | [Discussion] Reflection-based constructor autowiring (scope clarification) | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-129709@lists.php.net to get a copy of this message | ||
Hello internals,
My name is Zoltán Gyárfás András (aka Zoli). I am a long-time PHP developer, primarily working
on large PHP codebases where constructor-based dependency injection is used extensively.
Before preparing a formal RFC, I would like to clarify the scope and intent of a small, opt-in idea
and gather early feedback from the list.
The idea is to introduce a minimal reflection-based constructor autowiring primitive into the core,
exposed explicitly via the Reflection API, for example:
ReflectionClass::newInstanceAutowire(array $overrides = [], ?callable $resolver = null): object
This proposal is intentionally narrow. To avoid misunderstandings, I would like to clearly explain
what the idea does and does not include.
Key points of the idea, explained in detail:
1. Explicit opt-in (no change to the new operator)
Autowiring would only happen when the developer explicitly calls the new Reflection API.
The semantics of the new operator remain unchanged. Existing code paths are not affected, and there
is no implicit dependency resolution anywhere in the language.
2. No global container or service registry
The proposal does not introduce a global container, service locator, or registry of any kind.
Each autowiring operation is local to the call site and bound to the current call stack. No global
state is created or reused across calls.
3. No implicit interface-to-implementation mapping
When a constructor depends on an interface or abstract class, the core does not attempt to guess or
discover a concrete implementation.
Such mappings are inherently policy decisions and vary widely between frameworks. Instead, an
explicit resolver callback is required if non-instantiable types are involved.
4. Scalar parameters require overrides or defaults
Scalar and builtin parameters are treated as configuration values. The core does not read
environment variables, configuration files, or globals.
As a result, scalar parameters must either have default values or be provided explicitly via the
$overrides argument.
5. Interface and abstract types require an explicit resolver callback
Interfaces and abstract classes are never instantiated automatically.
If encountered during autowiring, the core either delegates resolution to the provided resolver
callback or fails with a clear exception. This keeps architectural decisions firmly in userland.
6. Deterministic circular dependency detection
Autowiring necessarily builds an object graph. The proposal includes mandatory detection of circular
dependencies within that graph.
When a cycle is detected, a deterministic and descriptive exception is thrown, rather than allowing
infinite recursion or a stack overflow.
7. Request-scope caching of constructor metadata only
For performance reasons, constructor metadata (parameter lists, types, defaults) may be cached for
the duration of the request.
No object instances are cached, no lifetimes are managed, and no persistent or global caches are
introduced.
At this stage, I am primarily interested in feedback on whether this level of restraint is
sufficient to keep the feature aligned with PHP’s “mechanism, not policy” philosophy, and
whether there are any immediate concerns regarding reflection, error handling, or performance.
If the direction seems reasonable, I plan to follow up with a draft RFC on wiki.php.net that
incorporates the feedback from this discussion.
Thank you for your time and insights.
Best regards,
Zoli
eng. ANDRÁS Zoltán-Gyárfás
---------------------------------------
tel: +40 745 797 798
mail: azolee@gmail.com