How does Laravel 5 make an instance to be passed automatically if we just set Type Hinting in the parameter in a function?

Asked

Viewed 1,000 times

4

I believe that this is a fully valid curiosity, since it greatly facilitates and speeds up development.

I always analyze the code of the frameworks I use, such as Cakephp 2, Laravel 4 and Symfony 2.

I just started working with Laravel 5 and I realized that in it there’s a feature that I’ve never seen in any of the frameworks. It’s the automatic passing of an instance to the argument of a method of a controller or route, or any other class of the framework, simply by defining the Type Hiting of function.

Example:

class AuthController extends Controller
{
    public function getIndex(Request $request, UrlGenerator $url)
    {
       $request->get('nome');
    }
}

By doing this in the parameters of getIndex, automatically, instances of classes are passed to the method. So, if I don’t want to use UrlGenerator, I can simply remove the parameter declaration from that method, which it will not be passed by argument.

I mean, no matter the position of the parameters, it always gives me the instance of the typed argument simply because I passed it there.

Another example:

 public function getIndex($id, Request $request){}

Or

public function getIndex(Request $request, $id) {}

How is it possible to do this in php? How Laravel does that?

1 answer

3


This is only possible thanks to Service Container of Laravel. It is an implementation of Ioc (Inversion of Control) and DI (Dependency Injection) which aims to reduce coupling between classes and facilitate in the construction of objects.

It solves classes in two ways: Through a Binding, which is a kind of configuration where we inform which instance should be returned if a certain class is injected:

<?php 

app()->bind(MinhaClasse::class, function () {
    return new MinhaClasse(new OutraClasse, 'algum-argumento');
});

Basically here we are registering on Service Container which he must return to instantiating a specific class. This can be user to tie in our code a specific implementation of an interface. Those bindings are usually written in the classes of Service Provider of Laravel.

The second form is similar to the first and the Laravel uses the Reflection API PHP to instantiate these classes. But this will not work with Interfaces and with classes that have dependencies in the constructor that also cannot be solved by Service Container (one string with the API key, or an interface without Binding for example).

This makes it possible for all classes that are executed within of can inject at the time of class instantiation the necessary dependencies.

Basically Laravel turns to the Service Container and asks for that class. Underneath the scenes Laravel actually does this:

<?php 

app()->make(MinhaClasse::class);

This way of working is not unique to Laravel. There are other implementations of Dependency Injection in other frameworks, such as Zend/Di or the thephpleague/container.

To get an idea of how to do it, you can get inspired by this class: https://github.com/thephpleague/container/blob/master/src/ReflectionContainer.php

  • The method resolveClass is who does the work on Laravel. The class Container is what makes all the magic ;).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.