On Fri, Jan 12, 2024, at 4:44 PM, Rasmus Schultz wrote:
> Dear Figs :-)
>
> I've been hard at work these past couple of months, since I became 
> interested in the Service Provider PSR proposal again.
>
> I've spent many nights and have read through every issue and comment on 
> the issue tracker, and many old discussions here on the group, going 
> back as far as 6-7 years.
>
> I eventually ended up writing a proper draft for the PSR itself, as 
> well as a meta-document. And the updated proposal features optional 
> dependency enumeration, which you can read more about in the new 
> documents.
>
> You can find the new documents here:
>
> https://github.com/container-interop/service-provider
>
> This is a call for participation! I'd like to invite you to read the 
> drafts, comment on open issues, and contribute to discussions.
>
> Note that the "Issues" tab on the Github page is intended for issues 
> with the documents themselves, while the "Discussion" tab should be 
> used to propose ideas and discuss implications. ("there is a problem 
> with the spec" is an issue, while "how about this cool idea" is a 
> discussion.)
>
> I worked hard on this, and I'm taking the lead on another push to bring 
> this proposal to fruition, so I really hope some of you will take an 
> interest. Let's make it happen! :-)
>
> Thank You.
>
> Regards,
>   Rasmus Schultz

First off, thank you for resurrecting this topic.  I argued at the time of 
PSR-11 that the registration side was at least as important as the extraction 
side, and while I eventually came around on PSR-11 doing just the extraction 
part, I still believe the registration side is just as important.

That said, I don't think the current approach is viable.  I appreciate the 
simplicity argument for it over some of the alternatives, but it has one rather 
large flaw: It's incompatible (as far as I can tell) with compiling or 
optimizing containers.

To be very brief (more for the audience than for Rasmus, who I'm sure knows 
this already), some containers do all registration at runtime.  In that case, 
having every provider return an array of closures works well enough.  Others 
collect the service and dependency information once and code-generate a file or 
files that are used at runtime, with all the information pre-computed so the 
registration process does not need to run.

The quality of compiled container output varies widely, but all of them are 
substantially faster than a runtime container.  The best use generated match() 
statements, which benchmarks show are faster than even a chain of if-statements 
and, likely, an array lookup to a closure.  In the ideal case, you end up with 
generated code like:

public function get(string $service): mixed
{
    return $this->cache[$service] ??= match($service) {
        \App\A::class => new \App\A(),
        \App\B::class => new \App\B($this->get(\App\A::class)),
        \App\C::class => new \App\C($this->get(\App\A::class), 
$this->get(\App\C::class), 'some-constant'),
        default => throw new Exception(...);
    };
}

(You could actually do better than that, but I'm trying to keep it simple.)

The problem is, Closures cannot be serialized.  That means the factory approach 
as presented is incompatible with a compiled container; the only option would 
be to do some kind of AST parsing of the closure and regenerate its code, 
which... ew.

So standardizing registration on a mechanism that is incompatible with 
high-performance containers seems... not great.  I realize the alternatives 
with standard file formats have their own challenges, which is why they haven't 
been done yet.

I think probably the best option would be to effectively standardize something 
along the lines of Symfony's compiler passes, with a more modern API design.  
Pass a ContainerBuilder to a series of objects with some standard interface for 
defining and modifying service entries.  With the data then in-memory in an 
abstracted form, it could be used at runtime or compiled, as the container 
implementation prefers.

Part of me wants to build such a compiler-pass system on top of PSR-14, since 
it's virtually the same model.  (And that kind of "registration pass" was an 
explicit design target of PSR-14.)  It could probably be done in a 
PSR-14-optional way.

--Larry Garfield

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to php-fig+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/ac46ca26-b5e8-4aa1-a1d8-d9fdb78bec08%40app.fastmail.com.

Reply via email to