1

I can't get why laravel tries to create my class itself, without using my method. I can see that IoC binding is executed (POINT 1 is shown). But singleton method is being never executed. Why?

In my service provider (not deferred):

/**
 * Register the service provider.
 *
 * @return void
 */
public function register()
{
    echo "POINT 1"; // I can see this one
    $this->app->singleton(\App\Services\FooBar::class, function($app)
    {
        echo "POINT 2\n"; // Does not comes here
        return new FooBar($params);
    });
}

I try to use typehinting to resolve dependencies when creating a class:

class Test
{
    public function __construct(FooBar $fooBar)
    {

    }
}

I see that laravel tries to create FooBar to inject it, but can't resolve FooBar's dependencies. They could be resolved, if laravel would call service provider callback, but it does not. Why? How to make laravel use that callback for that class?

avasin
  • 9,186
  • 18
  • 80
  • 127
  • How does the FooBar class looks like ? What are their dependencies. Laravel will not be able to resolve dependencies if they are not type hinted ie ``__construct($dep)`` will not work as you require ``$dep`` but dont pass the type of it. So you have to either ``__construct(SomeClass $dep)`` or ``__construct($dep=null)``. – Maksym Jun 26 '15 at 09:46
  • So if your class looks like this then you should be able to just call ``app('Test')``. Do you get any specific error ? By the way this way you dont need to call ``$this->app->singleton`` unless you want to manually resolve the dependencies. – Maksym Jun 26 '15 at 13:19

2 Answers2

1

It is because when you are binding a class to IoC container you are not immediately calling the closure. Instead when you need to actually do some action on your class from container you call App::make('class') which would fire the closure and give you the value that was returned from it. So for example

/**
 * Register the service provider.
 *
 * @return void
 */
public function register()
{
    echo "POINT 1"; // I can see this one
    $this->app->singleton(\App\Services\FooBar::class, function($app)
    {
        echo "POINT 2\n"; // Does not comes here
        return new FooBar($params);
    });

    $this->app->make(\App\Services\FooBar::class); //here POINT 2 will be called first.
}
Maksym
  • 3,276
  • 3
  • 22
  • 27
  • 1
    i understand this, but i can't call App::make for DI - it should be done automatically. How it is possible to achieve that? – avasin Jun 26 '15 at 08:47
  • I don't understand what you are trying to achieve. Can you provide some example of what you want to do ? – Maksym Jun 26 '15 at 08:48
  • I want to make dependency injection working. Laravel allows to specify, for example parameters in constructors/etc with typehinting, and if it is possible it tries to resolve dependencies automatically. But it seems that laravel allows to do that only for contracts, not for class names. – avasin Jun 26 '15 at 08:51
  • Of course it does not. It will almost always be able to resolve dependencies from constructor if needed. It just depends on what you are trying to achieve. But mostly thing like ``$app->make(\App\Services\FooBar::class)`` will work unless in constructor you are passing some interfaces that were not binded to concrete implementations. In that case you will get ``BindingResolutionException``. Update your question and show what exacly does not work so I can help. – Maksym Jun 26 '15 at 08:57
  • Updated. Thanks a lot! – avasin Jun 26 '15 at 09:20
1

Instead of closure (that will not work), use boot() method to initiate your service.

/**
 * @param \App\Services\FooBar $foobar
 */
public function boot(\App\Services\FooBar $foobar)
{
    $foobar->setOptions(['option' => 'value']);
}

It will launch right after service will be instantiated.

Maxim Lanin
  • 4,351
  • 24
  • 32