Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Apply inflectors right after the concrete is resolved #266

Closed
Arcesilas opened this issue Nov 30, 2024 · 2 comments
Closed

Comments

@Arcesilas
Copy link
Contributor

I'm not sure the title is self-explanatory...

Since a picture is worth a thousand words, here is an example (with a few files):

class Logger
{
    public function log(string $message): void
    {
        echo $message . PHP_EOL;
    }
}
interface LoggerAwareInterface
{
    public function setLogger(Logger $logger): void;
}
use League\Container\ServiceProvider\AbstractServiceProvider;
use League\Container\ServiceProvider\BootableServiceProviderInterface;

class LoggerProvider extends AbstractServiceProvider implements BootableServiceProviderInterface
{
    public function provides(string $id): bool
    {
        return Logger::class === $id;
    }

    public function register(): void
    {
        $this->getContainer()->add(Logger::class);
    }

    public function boot(): void
    {
        $this->getContainer()->inflector(LoggerAwareInterface::class)
            ->invokeMethod('setLogger', [Logger::class]);
    }
}
class Foo implements LoggerAwareInterface
{
    private Logger $logger;

    public function setLogger(Logger $logger): void
    {
        $this->logger = $logger;
    }

    public function doSomething(): void
    {
        $this->logger->log('Doing something');
    }
}
use League\Container\ServiceProvider\AbstractServiceProvider;

class FooProvider extends AbstractServiceProvider
{
    public function provides(string $id): bool
    {
        return Foo::class === $id;
    }

    public function register(): void
    {
        $this->getContainer()->add(Foo::class)
            ->addMethodCall('doSomething');
    }
}

And a simple test script:

require __DIR__ . '/vendor/autoload.php';

$container = new Container();

$container->addServiceProvider(new LoggerProvider());
$container->addServiceProvider(new FooProvider());

$foo = $container->get(Foo::class);

This script gives the following error: PHP Fatal error: Uncaught Error: Typed property Foo::$logger must not be accessed before initialization

This happens because the inflector is not applied immediately when the concrete is resolved (in the Definition class), but much later, when the Container sends it. A workaround is to manualy call the setter in the boot() method of the Service Provider, but then the inflector becomes pointless.

Is it worth considering applying inflectors earlier (in Definition::resolveNew(), before `invokeMethods() is called, apparently) or is this behavior by design?

I personnally think it's worth considering (obviously), since when I invoke methods on an object reolved by the container, I expect it to be fully usable.

I've quickly tried something before opening this issue and it seems there is an infinite loop if we try to apply inflectors in Definition immediatly before the invokeMethods call...

@philipobenito
Copy link
Member

philipobenito commented Nov 30, 2024 via email

@Arcesilas
Copy link
Contributor Author

Thanks for your quick answer!

I understand what you mean. My use case was loading configuration file and wanted the logger to be ready in order to display information on the command line. Actually, I was configuring my app, not Container. This is why I got confused.

Thanks again for your enlightening explanation as always!

@Arcesilas Arcesilas closed this as not planned Won't fix, can't repro, duplicate, stale Nov 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants