web-dev-qa-db-ja.com

Laravel=のReflectionはどのように機能しますか?

Laravelのリフレクションは実際にどのように機能しますか?

デバッグして、Laravelがコントローラーのコンストラクターまたはメソッドでリフレクションを使用して依存関係とサブ依存関係を解決し、それを返す方法を確認しようとしました。

しかし、私はそれが難しいことに気づき、その50%を見て理解することさえ非常に複雑です。クラスからクラスにジャンプして、私は本当にそれを見ることができません。理解の低い結果でそれをデバッグすることにより、私は数回試しました。

私はこれとリフレクションに非常に感銘を受けており、Laravel=がそれを使用する方法は私の心を燃やします—それはただ美しいだけです。ステップバイステップ。

ルートをたどってから、最後にdd($x)を取得します。ここで、_$x_はメソッド引数からのものであり、_TestClass2_の別の依存関係を持つTestClassです$x = new TestClass(new TestClass2());で構築する必要があります

これらは美しい仕組みと建築だと思いますが、これを理解することは非常に悪いことです。

繰り返しになりますが、私の質問は、Laravelのリフレクションは実際にどのように機能しますか?


それはddの人たちについてではありません... ddなしで言いましょう。先ほど言ったように、このオブジェクトを_class method_からインスタンス化したとき。ダンプするのではなく、reflectionによって_method injection_から取得するだけです。

ddは単なる例です。 die(var_dump());になることもあり、動作します

25
Krystian Polska

Laravelは、いくつかのコンポーネントにPHPの reflection API を使用します。これらのうち、制御の反転(IoC) dependency injection container およびコントローラー メソッドインジェクションは、開発者に最もよく見えます。

リフレクションの使用をより明確に説明するために、ここでは劇的にLaravelの IoCコンテナークラス を使用して構築されたルーチンの簡易バージョンを示しますコンストラクター注入によるオブジェクトの依存関係:

_function build($className) 
{
    $reflector = new ReflectionClass($className);
    $constructor = $reflector->getConstructor();

    foreach ($constructor->getParameters() as $dependency) {
        $instances[] = build($dependency->getClass()->name);
    }

    return $reflector->newInstanceArgs($instances);
}
_

ご覧のとおり、この概念を理解するのはそれほど難しくありません。コンテナは、PHPの ReflectionClass を使用してオブジェクトのコンストラクター内のクラスの名前を検索し、これらの名前のそれぞれを再帰的にループして、依存関係ツリーに各オブジェクトのインスタンスを作成します。これらのインスタンスを使用して、build()は最終的に元のクラスをインスタンス化し、コンストラクターに引数として依存関係を渡します。

コントローラメソッドインジェクションは、上記と同じコンテナ機能を使用して、メソッドパラメータとして宣言された依存関係のインスタンスを解決しますが、クラスの依存関係を分離するために少し余分なロジックが必要ですルートパラメータから:

_function dispatch(Route $route, Controller $controller, $methodName) 
{
    $routeParameters = $route->parametersWithoutNulls();
    $method = new ReflectionMethod($controller, $methodName);

    foreach ($method->getParameters() as $index => $parameter) {
        $class = $parameter->getClass();

        if ($class !== null) {
            $instance = build($class->name);
            array_splice($routeParameters, $index, 0, [ $instance ]);
        }
    }

    $controller->callAction($methodName, $routeParameters);
}
_

繰り返しになりますが、この適応は、反射が果たす役割を強調するためにスリム化されており、前述のbuild()関数に依存しています。 ControllerDispatcher クラスは、PHPの getParameters() メソッドを使用します ReflectionMethod コントローラーメソッドが期待するパラメーター。次にこれらをループして、コンテナーから解決できる依存関係を表すパラメーターを見つけます。次に、見つかった各依存関係をルートパラメーターの配列にスプライスし、ルートに定義されたコントローラーメソッドに渡します。詳細については、 RouteDependencyResolverTrait を参照してください。

アプリケーションのブートストラッププロセスを無視する場合、この依存性注入カスケードは通常Laravel=がリクエストをルートにマッピングし、リクエストをどのコントローラーに渡すかを決定します。Laravelは最初にコンテナからコントローラーのインスタンスを解決し、コンストラクターが注入した依存関係を構築します。次に、Laravelは適切なコントローラーメソッドを見つけて、必要に応じて引数。

ここに示すように、Laravel=はリフレクションを使用してこれらのツールを実装するために比較的単純な手法を使用します。ただし、この回答に示す例とは異なり、フレームワークは多くの追加コードを追加して、堅牢で柔軟なものにします今日のままです。

48
Cy Rossignol