Search code examples
phplaravelinversion-of-controlservice-provider

Service Providers and IoC in Laravel


I am going through the tutorial here, and I've run accross the following block of code in the ServiceProvider.

public function register()
{
    $this->app->bind("chat.emitter", function ()
    {
        return new EventEmitter();
    });
    $this->app->bind("chat.chat", function ()
    {
        return new Chat($this->app->make("chat.emitter"));
    });
    $this->app->bind("chat.user", function ()
    {
        return new User();
    });
    $this->app->bind("chat.command.serve", function ()
    {
        return new Command\Serve($this->app->make("chat.chat"));
    });
    $this->commands("chat.command.serve");
}

public function provides()
{
    return [
        "chat.chat",
        "chat.command.serve",
        "chat.emitter",
        "chat.server"
    ];
}

I am somewhat confused by a couple things:

  1. Why don't the strings in the provides function (specifically "chat.server") match up to what is being bound in the register function? Isn't provides necessary to tell what IoC what is available and what will be bound?

  2. When something is bound by the app, what is the convention for the string used to bind it? For instance, in the above code, "chat.emitter" returns an EventEmitter, but the class EventEmitter has nothing to do with the chat folder. It is, in fact, located in the Evenement package. Furthermore, "chat" isn't the top of the namspace, Formativ is. Why isn't it "formativ.chat.user"? So, what's the standard here? What does every piece of that string mean?


Solution

  • Why don't the strings in the provides function (specifically "chat.server") match up to what is being bound in the register function? Isn't provides necessary to tell what IoC what is available and what will be bound?

    Looks like an error/typo in the tutorial. FWIW, user and server (chat.user/chat.server -- the mismatched providers) are pretty easy to swap when you're writing quickly.

    When something is bound by the app, what is the convention for the string used to bind it?

    There is none. These service providers are meant to be global (as in, the entire world) identifiers for a service. There's no enforced naming convention, and from what I've seen Laravel is a small/insular enough community that this hasn't been a major problem. If I was going to redistribute a service provider I'd use a naming convention something like

    companyname_servicename
    

    The companyname portion being a unique namespace for my company/project, and the servicename identifying what the service did. While not 100% deterministic in avoiding namespace collisions, this would ensure folks would need to go out of their way to chose a name that would collide with mine.

    You can't derive anything about the underlying class from the service name -- even if you could, the whole point of the IoC container is to let users swap in different implementations if they want. This means even if you could derive a class name from a service name, you don't know what some other developer and/or third party package has done.

    Hope that helps!