Maison  >  Article  >  développement back-end  >  problème et solution de commande de passage de paramètre du contrôleur laravel5.5

problème et solution de commande de passage de paramètre du contrôleur laravel5.5

*文
*文original
2018-05-10 16:34:012289parcourir

Le contrôleur de laravel5.5 offre la possibilité d'injecter automatiquement en fonction du type de paramètre de méthode. Mais parfois, cela est légèrement gênant, ce qui se reflète dans le fait que l'injection des paramètres de méthode n'est pas entièrement basée sur le nom du paramètre. Si l'ordre des paramètres entrants est modifié, cela provoquera une erreur de non-concordance de type. Cet article résoudra le problème à partir d’une analyse approfondie de son principe d’injection.

1. Conception des étapes d'injection des paramètres de la méthode du contrôleur

1. Ajoutez des routes dans /routes/web.php

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

2. Écrivez le fichier du contrôleur DiaryController Place. php sous le chemin /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. Créez le modèle AppDiary et installez-le dans la base de données (omis)

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

4. méthode du contrôleur

Ouvrez le navigateur et saisissez : "http://127.0.0.1//diary/show/4/12"

À ce moment, la valeur du champ titre et l'id=4 dans le journal de la table de données sont affichés. 12

2. Description du type de paramètre d'injection

Remarque : Laravel générera une instance basée sur les variables {diary} et {page} correspondantes dans l'itinéraire de la requête. et les types de paramètres de méthode requis dans la méthode du contrôleur. Object et injectez-le dans la méthode du contrôleur

Il existe trois situations pour différents types de paramètres :

Si le type de paramètre implémente UrlRoutable. interface (c'est-à-dire héritée de IlluminateDatabaseEloquentModel), puis dans le modèle Recherchez la table correspondant à l'objet pour l'enregistrement dont la valeur d'identification est la valeur du paramètre correspondant dans l'itinéraire et construisez l'objet modèle

2. Si le type de paramètre est un type personnalisé (l'interface UrlRoutable n'est pas implémentée), laravel construira Inject après un objet

3 si le type de paramètre est le type de données de base et le nom est le nom défini dans. le paramètre de routage, puis obtenez la valeur du paramètre de routage ;

4. Si le type de paramètre Il s'agit d'un type de données de base, mais le nom n'est pas défini dans les paramètres de routage. utilisez la valeur par défaut, sinon le système génère une erreur.

3. Analyse des problèmes actuels avec les paramètres injectés

En référence au framework Spring MVC de Java, l'injection de type de paramètre de laravel présente encore des défauts, principalement reflétés dans le fait qu'elle n'est pas injectée entièrement selon le nom du paramètre.

1. Si vous modifiez l'ordre des paramètres du contrôleur, une erreur de transfert de type de paramètre se produira. Si vous modifiez l'ordre des paramètres de la méthode show contrôlée par DiaryController, une erreur se produira :

<?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. Puisque le type de paramètre est un type de données de base (voir 2 (3)), ce n'est pas un paramètre injecté selon le nom, alors changez le code comme suit et il fonctionnera également normalement

<?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 Analyse du code source d'injection des paramètres de la méthode du contrôleur

1 Le type de paramètre qui implémente l'interface UrlRoutable est construit par le middleware de routage IlluminateRoutingMiddlewareSubstituteBinding

    public function handle($request, Closure $next)
    {
        $this->router->substituteBindings($route = $request->route());
        $this->router->substituteImplicitBindings($route);
        return $next($request);
    }
Méthode substitutImplicitBindings d'IlluminateRoutingRouter

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

    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);
        }
    }
dans la méthode solveForRoute de IlluminateRoutingImplicitRouteBinding Notes supplémentaires :

La méthode setParameter de l'objet $route (type IlluminateRoutingRoute. ) est appelé ici pour indiquer le type de paramètre du modèle (voir 2 (1) ) L'instance de modèle est injectée en faisant correspondre le type de paramètre et le nom du paramètre en même temps

2. D'autres types de paramètres de contrôleur sont liés lorsque exécution du contrôleur de routage

L'élément clé réside dans la méthode de répartition de IlluminateRoutingControllerDispatcher Implémenté dans :

    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));
    }
Appelez la méthode solveClassMethodDependencies

  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;
    }
Résumé du problème :

1. Paramètres du modèle (voir 2 (1)) et noms dans les paramètres de routage Les types de base définis dans (voir 2 (3)) doivent d'abord être passés dans la méthode du contrôleur dans l'ordre défini dans la route, sinon, une erreur d'incompatibilité de type se produira ;

2. Les types personnalisés (voir 2) (2)) et les paramètres de type de base dont les noms ne sont pas définis dans les paramètres de routage (voir 2 (4)), sont transmis dans l'ordre d'apparition dans la méthode du contrôleur.

5. Résolution du problème

Ouvrez le fichier /vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php,

modifiez la méthode solveMethodDependencies avec le code suivant

    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;
    }
Après la modification, les paramètres de la méthode du contrôleur sont injectés complètement en fonction de leurs noms et types. Le code devient plus concis et la fonction est plus puissante !

Si le paramètre n'est pas défini dans la route et qu'aucune valeur par défaut n'est fournie, null sera injecté.

Recommandations associées :

Explication détaillée de la façon dont PHP implémente l'injection automatique de dépendances basée sur le mécanisme de réflexion

Qu'est-ce que l'injection de dépendances ?

Comment utiliser l'interface correspondante de Laravel 5.5 ?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn