Hi Larry, hi Ben,

Thank you - these questions are fair, and I agree they go to the core of what 
needs to be justified.

Clarifying the goal

The intent is not to provide an alternative to existing DI containers. If 
framed that way, I agree there is no strong case. What I am exploring is 
whether there is room for a small, low-level mechanism that containers (and 
projects that do lightweight wiring without a full container) could optionally 
build on.

These are two different goals, and the first one is explicitly not what I am 
aiming for.

Where a potential “win” could exist

At this stage, this is a hypothesis, not a conclusion. The possible benefits I 
am investigating are:

Standardizing a common runtime mechanism
Many projects independently implement very similar runtime autowiring loops: 
constructor inspection, type handling, cycle detection, and error reporting. 
While all of this can be done in userland, it is repeatedly reimplemented with 
small differences and edge cases.

Engine-level access to metadata with request-scope caching
Userland implementations rely heavily on Reflection objects and repeated 
allocations. In principle, an engine-level primitive could work directly with 
internal structures and cache a simple constructor plan for the duration of a 
request. Whether this results in a meaningful performance improvement needs to 
be measured.

More consistent diagnostics for failure cases
When runtime autowiring fails today, error messages and behavior vary widely 
between implementations. A shared primitive could provide deterministic and 
actionable diagnostics for common failure modes such as missing scalars, 
non-instantiable dependencies, or circular graphs.

Larry’s lazy-proxy example is a good reference for what “worth it” looks like: 
removing a large amount of complex or ugly code by using engine-only 
capabilities. I am not claiming the same level of benefit here. The question is 
whether the points above add up to a smaller but still meaningful win.

Why this cannot just be asserted

I agree that “this can be done in userland” is the default position, and that 
any move toward core needs evidence. At this point, I do not think the case can 
be made without concrete data.

Next step
Based on your feedback (and Marco’s), my plan is to:

implement a reference userland version with the proposed semantics,
benchmark it against typical reflection-based autowiring approaches,
and, if useful, compare it to a small proof-of-concept extension implementing 
the same algorithm in C.

This should allow us to answer concretely:

whether there is a meaningful performance or complexity win,
and whether the primitive would be broadly useful enough across 
runtime-autowiring use cases to justify standardization.

If you have guidance on what you would consider a representative benchmark 
scenario or a meaningful threshold for “this belongs in core”, I would 
appreciate it.

Thanks again for the questions - they helped sharpen the problem statement.

Best regards,

Zoli



eng. ANDRÁS Zoltán-Gyárfás
---------------------------------------
tel: +40 745 797 798
mail: [email protected]

> On 29 Dec 2025, at 20:02, Ben Ramsey <[email protected]> wrote:
> 
> On Mon, Dec 29, 2025 at 10:24 Larry Garfield <[email protected] 
> <mailto:[email protected]>> wrote:
>> On Sun, Dec 28, 2025, at 3:39 AM, ANDRÁS Zoltán Gyárfás 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 am unclear what advantage this offers over the status quo, or who the 
>> intended user is.  Is the intent to be "an alternative to existing DI 
>> containers" (in which case, what does it offer that would make me use it 
>> instead of Symfony DI, PHP-DI, rolling my own, etc.), or is it "a tool that 
>> existing DI containers can use to be better" (in which case, how is it 
>> better than the existing options for them)?  Those are two different goals 
>> that would have two different designs.
>> 
>> For example, lazy object proxies already existed in user-space.  However, 
>> the amount of fugly code it required was high, so moving that logic into the 
>> engine where it could take advantage of engine-only features to provide a 
>> far cleaner API and better performance was a win, and allows the removal of 
>> lots of fugly code from existing projects (when they upgrade).  I'm not 
>> clear where such a win can be found with this proposal.
>> 
>> --Larry Garfield
> 
> 
> I meant to send this question yesterday—it pretty much sums up Larry’s 
> question, though:
> 
> What problem(s) does this solve that can’t or isn’t already solved by a 
> userland implementation?
> 
> I see a lot of detail on the technical aspects of what you’re proposing, but 
> I don’t see anything about why you’re proposing it.
> 
> Cheers,
> Ben
> 

Reply via email to