Hi Marco, thank you for the thoughtful feedback - I agree with the concerns you raised, as they help clarify the right next step.
On Reflection: my initial motivation for using ReflectionClass was that it already owns the “dynamic instantiation” surface (newInstance, newInstanceArgs) and provides an explicit opt-in entry point without introducing new global concepts. That said, I fully take your point that Reflection is primarily an inspection API and can be seen as a “deep trap” when it starts to look like a general-purpose factory. I don’t want to force that framing if it turns out to be the wrong abstraction. On “this can be done in userland”: I agree. The proposal is not about enabling something fundamentally impossible today, but about whether moving a very common runtime autowiring loop (constructor parameter analysis, type handling, cycle detection, diagnostics) closer to the engine could provide enough benefit to justify standardization. As you point out, that needs to be demonstrated, not assumed. Your suggestion to validate this in userland (or as an extension) first makes sense, and I plan to follow that path before pushing further on a core RFC. Concretely, the next steps I’m considering are: A reference userland implementation that follows the same strict semantics discussed (explicit overrides, resolver for non-instantiables, deterministic cycle detection, request-scope metadata caching). A small benchmark suite comparing: typical userland reflection-based autowiring approaches, the reference implementation, and, if feasible, a proof-of-concept extension implementing the same algorithm in C. Using that data to answer whether there is a meaningful performance or complexity win that userland alone cannot reasonably achieve. Regarding AoT / compiled factories: I agree that the proposed primitive naturally aligns better with runtime autowiring, and that many containers deliberately avoid runtime reflection for production paths. My intent was not to replace or constrain those approaches, but to explore whether a low-level helper could still be useful in non-compiled modes (development, dynamic plugins, fallback paths). Whether that use case is broad enough is exactly what the userland validation should clarify. If you have any guidance on what you would consider a representative benchmark or a meaningful performance threshold for “worth moving into core”, I’d appreciate it. Thanks again for the feedback, Zoli eng. ANDRÁS Zoltán-Gyárfás --------------------------------------- tel: +40 745 797 798 mail: [email protected] > On 29 Dec 2025, at 13:02, Marco Pivetta <[email protected]> wrote: > > Hey Zoli, > > On Sun, 28 Dec 2025 at 10:40, ANDRÁS Zoltán Gyárfás <[email protected] > <mailto:[email protected]>> wrote: >> 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 <http://wiki.php.net/> that incorporates the feedback from this >> discussion. >> >> Thank you for your time and insights. >> >> Best regards, >> >> Zoli >> > > I'm unconvinced about using reflection for this: reflection is thought of a > "deep trap" for inspecting and manipulating code in ways that aren't > generally possible in userland, and isn't really a factory. > Everything you described can be implemented in userland, using existing > reflection API. > > While I like the signature you are going with (or at least its direction), I > believe that a userland implementation that proves to be "so popular that > everyone would use it" is needed first. > > For instance, the implementation you propose already goes towards supporting > DI systems that do autowiring at runtime, excluding those that do some AoT > compilation of factories. > Also, unless provided by resolvers, all dependencies aren't cached in any way > (also something that tends to be configurable in various DI libraries). > > I suggest prroviding this as a userland library or extension first, > specifically to validate whether there is a substantial performance > improvement over current solutions. > > Marco Pivetta > > https://mastodon.social/@ocramius > > https://ocramius.github.io/ >
