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='diary'; 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); }
public function substituteImplicitBindings($route) { ImplicitRouteBinding::resolveForRoute($this->container, $route); }
public static function resolveForRoute($container, $route) { //从路由参数中获取参数值,$parameters为 ['diary':'4','page':'12'] $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); } }
public function dispatch(Route $route, $controller, $method) { //解析控制器方法的参数 $parameters = $this->resolveClassMethodDependencies( $route->parametersWithoutNulls(), $controller, $method ); if (method_exists($controller, 'callAction')) { //通过Illuminate\Routing\Controller的callAction调用控制器方法 return $controller->callAction($method, $parameters); } //直接调用控制器方法 return $controller->{$method}(...array_values($parameters)); }
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; }
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; }
Recommandations associées :
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!