search
HomeBackend DevelopmentPHP TutorialLaravel5.5 controller parameter passing order problem and solution

The controller of laravel5.5 provides the ability to automatically inject based on the method parameter type. But sometimes there is a slight inconvenience, which is reflected in the fact that the injection of method parameters is not entirely based on the parameter name. If the order of the incoming parameters is changed, it will cause a type mismatch error. This article will solve the problem from an in-depth analysis of its injection principle.

1. Controller method parameter injection step design

1. Add routing in /routes/web.php

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

2. Write the controller file DiaryController.php and put it in Go to the path of /app/Http/Controllers/Diary/

<?php
namespace 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 the model\App\Diary and install it into the database (omitted)

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Diary extends Model
{
    protected $table=&#39;diary&#39;;
    public $timestamps = false;
}

4. Access the controller method

Open the browser and enter: "http://127.0.0.1//diary/show/4/12"

At this time, the title field value and 12## of id=4 in the data table diary are output.

#2. Injection parameter type description

Description: Laravel will generate and inject instance objects based on the matching {diary} and {page} variables in the request route and the method parameter types required in the controller method. In the controller method,

There are three situations for different parameter types:

1. If the parameter type implements the UrlRoutable interface (that is, inherited from Illuminate\Database\Eloquent\Model), Then search the table corresponding to the model object for the record whose id value is the matching parameter value in the route, and build the model object;

2. If the parameter type is a custom type (the UrlRoutable interface is not implemented), then Laravel will construct an object and then inject it;

3. If the parameter type is a basic data type and the name is the name defined in the routing parameter, the value will be obtained from the routing parameter;

4. If the parameter type is a basic data type but the name is not defined in the routing parameter, use the default value if there is one, otherwise the system will prompt an error.

3. Analysis of current problems with injected parameters

Referring to Java's Spring MVC framework, laravel's parameter type injection still has flaws, mainly reflected in the fact that it is not injected entirely according to the parameter name.

1. If you change the order of controller parameters, a parameter type transfer error will occur. If you change the order of the parameters of the show method controlled by DiaryController, an error will occur:

<?php
namespace 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. Since the parameter type is a basic data type (see 2 (3)), it is not a parameter injected according to the name. Therefore, changing the code to the following will also run normally

<?php
namespace 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); 
  } 
}

4. laravel5.5 controller method Parameter injection source code analysis

1. The parameter type that implements the UrlRoutable interface is constructed by the 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);
    }

Illuminate\Routing\Router's substituteImplicitBindings method

    public function substituteImplicitBindings($route)
    {
        ImplicitRouteBinding::resolveForRoute($this->container, $route);
    }

Implemented in the resolveForRoute method of Illuminate\Routing\ImplicitRouteBinding

    public static function resolveForRoute($container, $route)
    {
        //从路由参数中获取参数值,$parameters为 [&#39;diary&#39;:&#39;4&#39;,&#39;page&#39;:&#39;12&#39;]
        $parameters = $route->parameters();
        //获取控制器的函数参数列表,此处传入UrlRoutable::class,只返回实现UrlRoutable接口的参数
        $signatureParameters = $route->signatureParameters(UrlRoutable::class);
        foreach ($signatureParameters as $parameter) {
            if (! $parameterName = static::getParameterName($parameter->name, $parameters)) {
                continue;
            }
            $parameterValue = $parameters[$parameterName];
            if ($parameterValue instanceof UrlRoutable) {
                continue;
            }
            //构建模型的实例(基础自Illuminate\Database\Eloquent\Model),此处为App\Diary
            $instance = $container->make($parameter->getClass()->name);
            //将参数值绑定到模型,参加Illuminate\Database\Eloquent\Model的resolveRouteBinding方法
            if (! $model = $instance->resolveRouteBinding($parameterValue)) {
                throw (new ModelNotFoundException)->setModel(get_class($instance));
            }
       //根据参数名称注入模型实例
            $route->setParameter($parameterName, $model);
        }
    }

Additional instructions:

The setParameter method of the $route object (Illuminate\Routing\Route type) is called here to illustrate the model The parameter type (see 2 (1)) is injected into the model instance by matching the parameter type and parameter name at the same time

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

The key part is implemented in the dispatch method of Illuminate\Routing\ControllerDispatcher:

    public function dispatch(Route $route, $controller, $method)
    {
        //解析控制器方法的参数
        $parameters = $this->resolveClassMethodDependencies(
            $route->parametersWithoutNulls(), $controller, $method
        );
        if (method_exists($controller, &#39;callAction&#39;)) {
            //通过Illuminate\Routing\Controller的callAction调用控制器方法
            return $controller->callAction($method, $parameters);
        }
        //直接调用控制器方法
        return $controller->{$method}(...array_values($parameters));
    }

Call the resolveClassMethodDependencies method

  public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
    {
        $instanceCount = 0;
        $values = array_values($parameters);
        //通过方法反射获取方法参数
        foreach ($reflector->getParameters() as $key => $parameter) {
        //如果有默认值则返回默认值,如果是自定义方法则构建实例返回
            $instance = $this->transformDependency(
                $parameter, $parameters
            );
            if (! is_null($instance)) {
                $instanceCount++;
                //自定义类型(未实现UrlRoutable接口)的实例注入
                $this->spliceIntoParameters($parameters, $key, $instance);
            } elseif (! isset($values[$key - $instanceCount]) &&
                      $parameter->isDefaultValueAvailable()) {
                //未在路由参数中定义,但有默认值的参数注入
                $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue());
            }
        }
        return $parameters;
    }

Summary of the problem:

1. Model parameters (see 2 ( 1)) and the basic types whose names are defined in the routing parameters (see 2 (3)) must first be passed into the controller method in the order defined in the routing, otherwise a type mismatch error will occur;

2. Custom types (see 2 (2)) and basic type parameters whose names are not defined in routing parameters (see 2 (4)) are passed in in the order of appearance in the controller method.

5. Problem fix

Open 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 the modification, the controller method parameters are injected completely according to the name and type. The code becomes more concise and the function is more powerful!

If the parameter is not defined in the route and no default value is provided, null will be injected.

Related recommendations:

Detailed explanation of PHP's method of automatic dependency injection based on reflection mechanism

What is dependency injection?

How to use the corresponding interface of Laravel 5.5?

The above is the detailed content of Laravel5.5 controller parameter passing order problem and solution. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
How does PHP identify a user's session?How does PHP identify a user's session?May 01, 2025 am 12:23 AM

PHPidentifiesauser'ssessionusingsessioncookiesandsessionIDs.1)Whensession_start()iscalled,PHPgeneratesauniquesessionIDstoredinacookienamedPHPSESSIDontheuser'sbrowser.2)ThisIDallowsPHPtoretrievesessiondatafromtheserver.

What are some best practices for securing PHP sessions?What are some best practices for securing PHP sessions?May 01, 2025 am 12:22 AM

The security of PHP sessions can be achieved through the following measures: 1. Use session_regenerate_id() to regenerate the session ID when the user logs in or is an important operation. 2. Encrypt the transmission session ID through the HTTPS protocol. 3. Use session_save_path() to specify the secure directory to store session data and set permissions correctly.

Where are PHP session files stored by default?Where are PHP session files stored by default?May 01, 2025 am 12:15 AM

PHPsessionfilesarestoredinthedirectoryspecifiedbysession.save_path,typically/tmponUnix-likesystemsorC:\Windows\TemponWindows.Tocustomizethis:1)Usesession_save_path()tosetacustomdirectory,ensuringit'swritable;2)Verifythecustomdirectoryexistsandiswrita

How do you retrieve data from a PHP session?How do you retrieve data from a PHP session?May 01, 2025 am 12:11 AM

ToretrievedatafromaPHPsession,startthesessionwithsession_start()andaccessvariablesinthe$_SESSIONarray.Forexample:1)Startthesession:session_start().2)Retrievedata:$username=$_SESSION['username'];echo"Welcome,".$username;.Sessionsareserver-si

How can you use sessions to implement a shopping cart?How can you use sessions to implement a shopping cart?May 01, 2025 am 12:10 AM

The steps to build an efficient shopping cart system using sessions include: 1) Understand the definition and function of the session. The session is a server-side storage mechanism used to maintain user status across requests; 2) Implement basic session management, such as adding products to the shopping cart; 3) Expand to advanced usage, supporting product quantity management and deletion; 4) Optimize performance and security, by persisting session data and using secure session identifiers.

How do you create and use an interface in PHP?How do you create and use an interface in PHP?Apr 30, 2025 pm 03:40 PM

The article explains how to create, implement, and use interfaces in PHP, focusing on their benefits for code organization and maintainability.

What is the difference between crypt() and password_hash()?What is the difference between crypt() and password_hash()?Apr 30, 2025 pm 03:39 PM

The article discusses the differences between crypt() and password_hash() in PHP for password hashing, focusing on their implementation, security, and suitability for modern web applications.

How can you prevent Cross-Site Scripting (XSS) in PHP?How can you prevent Cross-Site Scripting (XSS) in PHP?Apr 30, 2025 pm 03:38 PM

Article discusses preventing Cross-Site Scripting (XSS) in PHP through input validation, output encoding, and using tools like OWASP ESAPI and HTML Purifier.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),