Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel-Core: Why does Laravel store Aliases multiple times?

Laravel does in its core in Application.php register a lot of the Default Implementations like this:

'url' => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],

Which will in effekt call the method below two times

public function alias($abstract, $alias)
    {
        $this->aliases[$alias] = $abstract;
    }

resulting in the following values in Container->aliases:

"Illuminate\Routing\UrlGenerator" => "url"
"Illuminate\Contracts\Routing\UrlGenerator" => "url"

If I later call: $this->app->alias('url', 'App\Util\Portal\UrlGenerator'); it even stores it a thrid time in the Container im the alias array:

"App\Util\Portal\UrlGenerator" => "url" 

My Question:

Why does laravel store them all two or three and not override them? It should be sufficient to store the concrete class. But why does laravel store them all three? How can laravel tell, which one to resolve, when I now use App::make('url')? Laravel has now three to choose from, one interface and two implementations.

like image 354
Tim Schmidt Avatar asked Sep 22 '15 05:09

Tim Schmidt


1 Answers

After Sleeping a night over it and digging more in the code (could yet not be 100% verified in code yet) its most likely as that:

"Aliasing"

Is used in various ways/methods:

  1. It can mean alias a Facade (like URL to a FacadeClass). Which is something completely different(!?)
  2. It can mean mapping a so called "abstract" (term/string) like "url" to an "alias" which in laravel terms is then a class or(!) interface. Aliasing (as the method does above) does NOT directly have to do anything with binding.

"Binding"

Laravel Container has two properties in its Container class named $aliases and $bindings. Bindings hold the real binding of an "abstract" to a concrete class to instanciate! So every alias (as discribed above) needs to also(!) have a corresponding binding(!) from the "abstract" the concrete class to be instanciated.

Conclusion

In effect as written above, there are thre aliases (of concrete classes and interfaces) to the key/abstract "url". But they have nothing to do with the instanciating process. For the alias to work there additinally also needs to be a real binding!

So in effect "Container Aliases" allow you to access an existing binding with other classses or interface names.

  1. If you call Container::make() with any of the aliases, laravel will try to resolve them to the "abstract" (here "url").
  2. And then in a second step, this abstract "url" is then tried to resolve against the bindings (which is something completely different).
  3. If no binding is found for the alias, an error is thrown.

So you can have an arbitrary amount of aliases but only one binding and you have to have that single binding (additionally!).

(Interestingly, if you map an alias to the same class as the binding, it seems to end in an recursion error. But this also might be an xdebug problem).

like image 58
Tim Schmidt Avatar answered Nov 14 '22 23:11

Tim Schmidt