《拉拉维尔的倒影》是如何运作的?

拉拉维尔的反思是如何运作的?

我试图调试它,看看Laravel如何使用控制器的构造函数或方法中的反射来解决它们的依赖关系和子依赖关系,然后将其交还给我们。

但我发现这很难,而且很难看到甚至理解50%的内容。从一个班级跳到另一个班级,我真的看不到它。我尝试了几次,以较低的理解结果进行调试。

我对这一点和反思印象深刻,Laravel使用它的方式让我的心燃烧 - 它太美了。我希望完全理解这一点——整个过程——总的来说,而且是一步一步的。

从命中路由开始,到最终具有,比方说,where 来自方法参数,并且是具有另一个依赖项的,应该通过以下方式构造:dd($x)$xTestClassTestClass2$x = new TestClass(new TestClass2());

我认为这些都是美丽的机制和建筑,理解这一点是我非常想要的。

所以,我的问题是:拉拉维尔的反思是如何运作的?


这与男人无关...假设没有 .正如我之前所说 - 当我们从 .这不是关于倾倒它,它只是关于从.ddddclass methodmethod injectionreflection

这只是一个例子。它甚至可以,它会工作dddie(var_dump());


答案 1

Laravel将PHP的反射API用于多个组件。其中,inverson-of control (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);
}

同样,这种适应被精简,以突出反射所扮演的角色,并依赖于我们前面显示的功能。ControllerDispatcher 类使用 PHP 的 ReflectionMethodgetParameters() 方法来确定控制器方法需要哪些参数,然后遍历这些参数以查找表示它可以从容器中解析的依赖项的参数。然后,它将找到的每个依赖项拼接回路由参数数组中,并将这些参数传递回为路由定义的控制器方法。有关详细信息,请参阅 RouteDependencyResolverTraitbuild()

如果我们忽略应用程序引导过程,则当 Laravel 将请求映射到路由时,通常会为请求启动此依赖关系注入级联,然后确定要将请求传递给哪个控制器。Laravel首先从容器中解析控制器的实例,该实例构建出任何构造函数注入的依赖项。然后,Laravel 找到合适的控制器方法,并根据需要解析参数的任何更多依赖关系。

如图所示,Laravel使用相对简单的技术来使用反射来实现这些工具。但是,与本答案中显示的示例不同,该框架添加了大量附加代码,以使它们像今天一样健壮和灵活。


答案 2

推荐