Как работает Reflection в Laravel?

Как отражается в Laravel на самом деле?

Я попытался отладить его, чтобы увидеть, как Laravel использует отражение в конструкторе контроллера или методах для разрешения их зависимостей и подзависимостей, а затем и возвращает его нам.

Но мне было трудно, и очень сложно увидеть и даже понять 50%. Перепрыгивая из класса в класс, я не вижу его. Я несколько раз пытался отладить его с низкими результатами понимания.

Я очень впечатлен этим и отражением, и способ, которым использует Laravel, заставляет мое сердце гореть - это просто красиво. И я хочу полностью понять это - весь процесс - в целом и шаг за шагом.

Начиная с попадания маршрута в конец, скажем, dd($x), где $x является аргументом метода и является TestClass, который имеет другую зависимость от TestClass2, которая должна быть построена с помощью: $x = new TestClass(new TestClass2());

Я думаю, что это прекрасная механика и архитектура, и понимание этого - это то, чего я так хочу.

Итак, снова мой вопрос: как на самом деле отражается в Laravel?


Это не о dd парнях... Пусть говорят без dd. Так же, как я сказал ранее, - когда мы создали этот объект из class method. Это не о том, чтобы сбросить его, а просто из-за method injection на reflection.

dd был только примером. Он может даже быть die(var_dump());, и он будет работать

Ответы

Ответ 1

Laravel использует PHP API отражения для нескольких компонентов. Из них контейнер инкрементов управления (IoC) и контроллер метод наиболее заметен для разработчиков.

Чтобы более четко проиллюстрировать использование рефлексии, здесь резко упрощена версия рутины 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 использует getParameters() метод PHP ReflectionMethod, чтобы определить, какие параметры ожидает метод контроллера, а затем перебирает их, чтобы найти параметры, представляющие зависимости, которые он может решить из контейнера. Затем он объединяет каждую зависимость, которую он находит обратно в массив параметров маршрута, который он возвращает обратно к методу контроллера, определенному для маршрута. Подробнее см. RouteDependencyResolverTrait.

Если мы проигнорируем процесс начальной загрузки приложения, этот каскад инъекции зависимостей обычно начинается для запроса, когда Laravel сопоставляет запрос маршруту и ​​затем определяет, какой контроллер должен передать запрос. Сначала Laravel разрешает экземпляр контроллера из контейнера, который создает любые зависимые от конструктора зависимости. Затем Laravel находит соответствующий метод контроллера и разрешает любые зависимости для аргументов по мере необходимости.

Как показано здесь, Laravel использует относительно простые методы для реализации этих инструментов с использованием отражения. Однако, в отличие от примеров, показанных в этом ответе, структура добавляет много дополнительного кода, чтобы сделать их такими же надежными и гибкими, как сегодня.