On Sat, Mar 23, 2024, at 12:55 PM, Rasmus Schultz wrote:
> Yes, this is very similar to the code in my second post - and yes, no
> problem for basic factories like these to work in both compiled and
> run-time containers.
>
> For extensions, it gets more challenging - a callback based container
> doesn't have models and can't generate them from functions.
>
> In a nutshell, compiled containers are "data in, code out" - while
> run-time containers, in relation to data-based service providers, would
> be "have code, need data".
>
> Parsing code would be the only way to get from functions to models, but
> that isn't going to make any sense in the context of e.g. Pimple.
(Please stop top posting. :-) )
To make sure we mean the same thing, what do you mean by "Extensions"? I'm
imagining something like Symfony Compiler Passes where you can add "call this
method after the object is created" commands and such, which, honestly, would
be trivial to implement as PSR-14. (That kind of pattern was an explicit
design goal.)
You are correct that there's no meaningful way to turn
$container->factory(Foo::class, fn(ContainerInterface $c) => new
FooBar($c->get(Baz::class)));
into an AST, so that isn't something a unified mechanism could support. I
think where we disagree is whether that's fatal or not. I really don't think
it is, not when any reasonably performant container already doesn't support
that, because it's compiled anyway. (Something simple like Pimple is still
pretty fast at read time, but has the overhead of re-registration on every
request that slows it down.)
But if a Provider returned an array like this:
class Provider {
public function getServices() {
return [
Baz::class => new Service(Baz::class),
FooBar::class => new Service(FooBar::class, [new DefRef(Baz::class)],
];
}
}
That would be quite easy for Pimple-like containers to support, and map back
into a runtime model:
public function registerProvider(Provider $provider) {
foreach ($provider->getServices() as $name => $def) {
$this->factories[$name] = static fn(ContainerInterface $c) => new
($def->class)($def->args);
// OK, that line would be slightly more complicated for the arg handling,
but you get the idea.
}
}
And then its get() method looks exactly like it does today already. No issue.
The *only* thing that is unsupportable in the standard itself would be
class Provider {
public function getServices() {
return [
Foo::class => fn(ContainerInterface $c) => new
FooBar($c->get(Baz::class))),
];
}
}
Which I am completely OK with not supporting, for the flexibility that gets us.
Even without mentioning compilation, it wouldn't allow for other providers to
modify the arguments; they could only add post-creation method calls. An AST
approach would still allow a runtime container to have "alter hooks" if it
wanted.
--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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/php-fig/f6c8db16-a5d4-4dee-95b9-85e56a9c4fa3%40app.fastmail.com.