Laravel5.5コントローラーパラメータの受け渡し順序の問題と解決策

*文
リリース: 2023-03-18 09:08:02
オリジナル
2263 人が閲覧しました

laravel 5.5のコントローラーは、メソッドパラメータの型に基づいて自動的に注入する機能を提供します。ただし、メソッド パラメーターの注入が完全にパラメーター名に基づいていないという事実に反映され、受信パラメーターの順序が変更されると、型の不一致エラーが発生するため、少し不便になる場合があります。この記事では、その注入原理の詳細な分析から問題を解決します。

1. コントローラーメソッドのパラメーター挿入ステップの設計

1. /routes/web.php

Route::get('/diary/show/{diary}/{page?}','Diary\DiaryController@list');
ログイン後にコピー
にルートを追加します。2. コントローラーファイル DiaryController.php を作成し、パス /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. AppDiary モデルを構築し、データベースにインストールします (省略)

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Diary extends Model
{
    protected $table=&#39;diary&#39;;
    public $timestamps = false;
}
ログイン後にコピー

4. コントローラー メソッドにアクセスします

ブラウザを開いて、「http://127.0.0.1//diary/show/4」と入力します。 /12"

このとき、データテーブル日記のid=4と12のtitleフィールドの値が出力されます

2. インジェクションパラメータの型説明

注: laravelは、{diary}変数と{page}変数に一致しますリクエストのルーティングとコントローラー メソッド内で、必要なメソッド パラメーター タイプが生成され、コントローラー メソッドに挿入されます。

さまざまなパラメーター タイプには 3 つの状況があります。

1. パラメーター タイプが UrlRoutable インターフェイスを実装している場合 (つまり、継承されている場合)。 IlluminateDatabaseEloquentModel から)、オブジェクトに対応するテーブルで、ID 値がルート内の一致するパラメーター値であるレコードを検索し、パラメーター タイプがカスタム タイプの場合、モデル オブジェクトを構築します。 UrlRoutable インターフェイスは実装されていません)、laravel はオブジェクトを構築してそれを注入します ;

3. パラメーターの型が基本データ型で、名前がルーティング パラメーターで定義されている名前である場合、値はルーティングから取得されます。パラメータ;

4. パラメータ タイプが基本データ タイプであるが、その名前がルーティング パラメータ定義にない場合、デフォルト値がある場合はデフォルト値を使用します。それ以外の場合は、システムがエラーを表示します。

3. 注入されたパラメータに関する現在の問題の分析

Java の Spring MVC フレームワークを参照すると、laravel のパラメータ型の注入にはまだ欠陥があり、主にパラメータ名に従って完全に注入されないという事実に反映されています。

1. コントローラーのパラメーターの順序を変更すると、パラメーターの型の転送エラーが発生します。たとえば、DiaryController によって制御される show メソッドのパラメーターの順序を変更すると、エラーが発生します:

<?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.パラメータの型は基本的なデータ型(2(3)参照)なので、名前の通りパラメータを注入するものではないので、以下のようにコードを変更すると、Laravel5.5コントローラーでも正常に動作します。メソッドパラメータインジェクションのソースコード分析

1. UrlRoutableインターフェイスを実装しました。パラメータの型は、ルーティングミドルウェアIlluminateRoutingMiddlewareSubstituteBinding実装によって構築されます

<?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); 
  } 
}
ログイン後にコピー

IlluminateRoutingRouterのsubstituteImplicitBindingsメソッド

    public function handle($request, Closure $next)
    {
        $this->router->substituteBindings($route = $request->route());
        $this->router->substituteImplicitBindings($route);
        return $next($request);
    }
ログイン後にコピー

は、IlluminateRoutingImplicitのresolveForRouteメソッドに実装されています。 RouteBinding

    public function substituteImplicitBindings($route)
    {
        ImplicitRouteBinding::resolveForRoute($this->container, $route);
    }
ログイン後にコピー

追加メモ:

ここでは $route オブジェクト (Illu) を呼び出します minateRoutingRoute 型) モデルを記述する setParameter メソッド パラメーター型 (2(1) 参照) は、パラメーター型とパラメーター名を同時に照合することでモデル インスタンスに注入されます

2。他のタイプのコントローラー パラメーターは、ルーティング コントローラーの実行時にバインドされます

重要な部分は、IlluminateRoutingControllerDispatcher のディスパッチ メソッド内にあります。 実装場所:

    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);
        }
    }
ログイン後にコピー

replaceClassMethodDependency メソッドを呼び出す

    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));
    }
ログイン後にコピー

問題の概要:

1. 2 (1) を参照)、ルーティング パラメーター (2 (3) を参照) で名前が定義されている基本型は、ルーティングに従っている必要があります。 で定義された順序が最初にコントローラー メソッドに渡されます。そうでない場合は、型不一致エラーが発生します。

2. ルーティング パラメーターで名前が定義されていないカスタム型 (2 (2) を参照) および基本型パラメーター (2 (2) 4) を参照) は、コントローラー メソッドで出現順に渡します。

5. 問題の修正

/vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php ファイルを開き、

resolveMethodDependency メソッドを次のコードに変更します

  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;
    }
ログイン後にコピー
変更後、コントローラー メソッドを完全に挿入しますパラメータの名前と型を変更すると、コードがより簡潔になり、関数がより強力になります。

パラメータがルートで定義されておらず、デフォルト値が指定されていない場合は、null として挿入されます。

関連する推奨事項:

PHP がリフレクションメカニズムに基づいて自動依存関係注入を実装する方法の詳細な説明

依存関係注入とは何ですか?

Laravel 5.5の対応するインターフェースを使用するにはどうすればよいですか?

以上がLaravel5.5コントローラーパラメータの受け渡し順序の問題と解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!