The problem and solution of laravel5.5 Controller's parameter sequence

Source: Internet
Author: User
Tags reflector
The laravel5.5 controller provides the ability to automatically inject according to the method parameter type. But sometimes it can be slightly inconvenient, reflected in the method parameter injection is not exactly according to the parameter name, if changing the order of incoming parameters will cause the type mismatch error. In this paper, the depth analysis of the principle of injection is solved.

First, the controller method parameter injection step design

1. Adding routes in/routes/web.php

Route::get ('/diary/show/{diary}/{page} ', ' diary\diarycontroller@list ');

2, write the controller file diarycontroller.php put under the/app/http/controllers/diary/path

<?phpnamespace app\http\controllers\diary;use App\http\controllers\controller;class DiaryController extends   controller{public    function Show (\app\diary $diary, $page =11) {        var_dump ($diary->title, $page); } }

3. Build model \app\diary and install to database (slightly)

<?phpnamespace app;use illuminate\database\eloquent\model;class Diary extends model{    protected $table = ' Diary ' ;    Public $timestamps = false;}

4. Access Controller method

Open Browser input: "HTTP://127.0.0.1//DIARY/SHOW/4/12"

The Title field value of id=4 in the output data table diary and 12

Second, injection parameter type description

Description: Laravel generates an instance object and injects it into the Controller method based on the type of method parameter required in the {diary} and {page} variables and controller methods that match the request route.

There are three scenarios for different parameter types:

1, if the parameter type implements the Urlroutable interface (that is, inherits from the Illuminate\database\eloquent\model), then finds the ID value in the table corresponding to the model object to match the parameter value in the route record, and constructs the model object;

2, if the parameter type is a custom type (no implementation of the Urlroutable interface), then Laravel constructs an object after injection;

3. If the parameter type is the underlying data type, and the name is the name defined in the routing parameter, the value is obtained from the route parameter;

4. If the parameter type is the underlying data type, but the name is not defined in the routing parameter, the default value is used if there is a default value, otherwise the system prompts for an error.

Analysis of existing problems in injection parameters

Referring to the Java Spring MVC Framework, Laravel's parameter type injection is still flawed, mainly in the absence of full parameter name injection.

1. If you change the order of the controller parameters, there will be parameter type passing errors, such as changing the order of the parameters of the Show method controlled by Diarycontroller, which will cause an error to occur:

<?phpnamespace app\http\controllers\diary;use App\http\controllers\controller;class DiaryController extends   controller{public    function Show ($page, \app\diary $diary) {        var_dump ($diary->title, $page); } }

2, because the parameter type is the underlying data type (see two (3)), not by the name of the parameters injected, so the code is changed as follows, will also run normal

<?phpnamespace app\http\controllers\diary;use App\http\controllers\controller;class DiaryController extends   controller{public    function Show (\app\diary $diary, $pag) {        var_dump ($diary->title, $PAG); } }

Four, laravel5.5 controller method parameter injection source code analysis

1. The parameter type of Urlroutable interface is implemented by routing middleware illuminate\routing\middleware\substitutebinding.

    Public function handle ($request, Closure $next)    {        $this->router->substitutebindings ($route = $request- >route ());        $this->router->substituteimplicitbindings ($route);        Return $next ($request);    }

The Substituteimplicitbindings method of Illuminate\routing\router

    Public Function substituteimplicitbindings ($route)    {        Implicitroutebinding::resolveforroute ($this container, $route);    }

Implemented in the Resolveforroute method of illuminate\routing\implicitroutebinding

    public static function Resolveforroute ($container, $route) {//Gets the parameter value from the route parameter, $parameters for [' Diary ': ' 4 ', ' page ':        ' n '] $parameters = $route->parameters (); Gets a list of function arguments for the controller, passed in Urlroutable::class here, returning only the parameters that implement the Urlroutable interface $signatureParameters = $route->signatureparameters        (Urlroutable::class); foreach ($signatureParameters as $parameter) {if (! $parameterName = Static::getparametername ($parameter->n            Ame, $parameters)) {continue;            } $parameterValue = $parameters [$parameterName];            if ($parameterValue instanceof urlroutable) {continue; }//Build an instance of the model (base from Illuminate\database\eloquent\model), here is app\diary $instance = $container->make ($par            Ameter->getclass ()->name); Bind the parameter values to the model, and participate in the Illuminate\database\eloquent\model resolveroutebinding method if (! $model = $instance->resolverout Ebinding ($parameterValue)) {throw(New Modelnotfoundexception)->setmodel (Get_class ($instance));        }//Inject model instance according to parameter name $route->setparameter ($parameterName, $model); }    }

Additional Instructions:

This calls the $route object (Illuminate\routing\route Type) Setparameter method, which describes the model parameter type (see two (1)) It is exactly the same as the parameter type and parameter name to inject the model instance

2. Other types of controller parameters are bound when running the routing controller

The key sections are implemented in the Illuminate\routing\controllerdispatcher dispatch method:

    Public Function Dispatch (Route $route, $controller, $method)    {        //parameters of the resolution controller method        $parameters = $this Resolveclassmethoddependencies (            $route->parameterswithoutnulls (), $controller, $method        );        if (method_exists ($controller, ' callaction ')) {            //Callaction Call Controller method            via Illuminate\routing\controller Return $controller->callaction ($method, $parameters);        }        Call the Controller method directly        return $controller->{$method} (... array_values ($parameters));    }

Calling the Resolveclassmethoddependencies method

 Public function resolvemethoddependencies (array $parameters,        Reflectionfunctionabstract $reflector) {$instanceCount = 0;        $values = Array_values ($parameters); Method parameters are obtained by means of the method parameter foreach ($reflector->getparameters () as $key = + $parameter) {//default value is returned if there is a default value, if the custom method is            Build instance returns $instance = $this->transformdependency ($parameter, $parameters);                if (! Is_null ($instance)) {$instanceCount + +;            Instance injection for custom type (not implemented Urlroutable interface) $this->spliceintoparameters ($parameters, $key, $instance); } elseif (! isset ($values [$key-$instanceCount]) && $parameter->isdefaultvalueavailable () {//is not defined in the route parameter but has a default value of parameter injection $this->spliceintoparameters ($parameters, $key, $parameter-            Getdefaultvalue ());    }} return $parameters; }

Summary of issues:

1, the model parameters (see two (1)) and the name of the underlying type defined in the routing parameters (see two (3)) must be in the order defined in the route first pass the controller method, otherwise there will be a type mismatch error;

2, the custom type (see two (2)) and the name is not defined in the routing parameters of the underlying type parameters (see two (4)), in the Controller method in the order in which they are passed in.

Five, the problem repair

Opens the/vendor/laravel/framework/src/illuminate/routing/routedependencyresolvertrait.php file,

Modify the Resolvemethoddependencies method to the following code

    Public function resolvemethoddependencies (array $parameters, Reflectionfunctionabstract $reflector) {        $ Methodparameters=[];        foreach ($reflector->getparameters () as $key = = $parameter) {            $name = $parameter->getname ();            $instance = $this->transformdependency ($parameter, $parameters);            if (!is_null ($instance)) {                $methodParameters []= $instance;            } ElseIf (!isset ($parameters [$name]) && $parameter->isdefaultvalueavailable ()) {                $methodParameters []= $parameter->getdefaultvalue ();            } else{                $methodParameters []=isset ($parameters [$name])? $parameters [$name]: null;            }        }        return $methodParameters;    }

After modification, the controller method parameters are injected exactly by name and type, and the code becomes more concise and powerful!

If the parameter is not defined in the route and no default value is provided, then NULL is injected.

Related recommendations:

An explanation of the method of automatic dependency injection based on reflection mechanism for PHP

What is dependency injection?

How can I use the Laravel 5.5 interface?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.