Search code examples
phpdependencieslaravel-5ioc-containerservice-provider

Laravel 5 Resolving dependencies in ServiceProvider


I have a class which acts like a storage (add/get item). I try to bind it as a singleton in one service provider, and resolve it in another's boot method.

The code is changed for simplicity.

app/Providers/BindingProvider.php

<?php namespace App\Providers;

use Illuminate\Support\Facades\Facade;
use Illuminate\Support\ServiceProvider as ServiceProvider;

class MyBindingFacade extends Facade {
    public static function getFacadeAccessor() {
        return 'my.binding';
    }
}

class MyBinding {

    protected $items = [];

    public function add($name, $item) {
        $this->items[$name] = $item;
    }
    public function get($name) {
        return $this->items[$name];
    }
    public function getAll() {
        return $this->items;
    }

}

class BindingProvider extends ServiceProvider {

    public function register() {
        $this->app->singleton('my.binding', function($app) {
            return $app->make('App\Providers\MyBinding');
        });
    }

    public function provides() {
        return [
            'my.binding',
        ];
    }
}

app/Providers/ResolvingProvider.php

<?php namespace App\Providers;

use Illuminate\Support\ServiceProvider as ServiceProvider;
use App\Providers\MyBinding;

class ResolvingProvider extends ServiceProvider {

    public function boot(MyBinding $binding) {
        $binding->add('foo', 'bar');

        // $manual = $this->app->make('my.binding');
        // $manual->add('foo', 'bar');
    }

    public function register() {}

}

app/Http/Controllers/WelcomeController.php

<?php
namespace App\Http\Controllers;

use App\Providers\MyBindingFacade;

class WelcomeController extends Controller {

    public function index()
    {
        dd(MyBindingFacade::getAll()); // debug items
    }
}

When I try to debug MyBinding state in my WelcomeController I'm getting empty item array. However, if I uncomment $manual part from my ResolvingProvider it returns an array containing 'foo' => 'bar'. Does it mean IoC resolution is broken in ServiceProvider::boot() method or am I misusing Laravel functionality?

Laravel version: 5.0.28

UPDATE: Added code sample from WelcomeController.


Solution

  • With this:

    $this->app->singleton('my.binding', function($app) {
        return $app->make('App\Providers\MyBinding');
    });
    

    You're saying: my.binding is a singleton and resolves to an instance of App\Providers\MyBinding.

    That doesn't mean that App\Providers\MyBinding is registered as singleton too. What you should do instead is this:

    $this->app->singleton('App\Providers\MyBinding');
    
    $this->app->bind('my.binding', function($app) {
        return $app->make('App\Providers\MyBinding');
    });
    

    Because the Facade binding uses $app->make() you should get the same instance you registered with $this->app->singleton() right above.