How does reflection in Laravel actually work?

I tried to debug it to see how Laravel uses reflection in a controller's constructor or methods to resolve their dependencies and sub-dependencies and then and give it back to us.

But I found it hard, and it's very complicated to see and to even understand 50% of. Jumping from class to class, I can't really see it. I tried a few times by debugging it with low results of understanding.

I am very impressed by this and by reflection, and the way Laravel uses it makes my heart burn—it's just beautiful. And I wish to fully understand that—the whole process—in general, and step by step.

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

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

So again, my question is: how does reflection in Laravel actually work?


It's not about dd guys... Let's say without dd. Just as I said earlier - when we have this object instantiated from the class method. It's not about dumping it, it's just about having it from method injection by reflection.

dd只不过是一个例子.它甚至可以达到die(var_dump());,而且会起作用

推荐答案

Laravel uses PHP's reflection API for several components. Of these, the inverson-of-control (IoC) dependency injection container and controller method injection are most visible to developers.

为了更清楚地说明反射的使用,下面是常规Laravel的IoC container class个使用的dramatically个简化版本,通过构造函数注入来建立对象的依赖关系:

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

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

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

As we can see, the concept isn't too difficult to understand. The container uses PHP's ReflectionClass to find the names of the classes in an object's constructor, and then loops through each of these names recursively to create instances of each object in the dependency tree. With these instances, build() finally instantiates the original class and passes the dependencies as arguments to the constructor.

Controller method injection uses the same container functionality shown above to resolve instances of dependencies declared as method parameters, but there's a bit of extra logic needed to separate class dependencies from route parameters:

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 ReflectionMethodgetParameters()方法来确定控制器方法需要哪些参数,然后遍历这些参数以查找表示它可以从容器解析的依赖项的参数.然后,它将找到的每个依赖项拼接回路由参数数组中,并将这些参数传递回为该路由定义的控制器方法.有关详细信息,请参见RouteDependencyResolverTrait.

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

As shown here, Laravel uses relatively simple techniques to implement these tools using reflection. However, unlike the examples shown in this answer, the framework adds a lot of additional code to make them as robust and flexible as they are today.

Laravel相关问答推荐

Laravel mail send Amazon SES不再支持TLS 1.0和TLS 1.1连接

在 Laravel 中设置多个 Vue 组件的问题

在 laravel 中查询此类数据的最佳做法是什么?

RuntimeException 未安装 Zip PHP 扩展

转储或 dd laravel 在结果前添加字符时出错

如何在使用 Laravel 在控制器中发送邮件之前更改邮件配置?

未找到 PHP 5.4 和 Laravel 类Memcached

如何在中间件 Laravel 中获取请求的控制器和操作的名称

Eloquent 的 Model::query() 是什么意思?

将 Laravel .env 变量添加到 Vue 组件

Laravel 5 Mime 验证

Laravel - DecryptException:'MAC 无效'

使用 Laravel 使用 2 个磁盘复制文件

如何在laravel中获取列值的平均值

Lumen/Laravel 6:调用未定义的函数 array_except()

Laravel X-CSRF-Token 与 POSTMAN 不匹配

Laravel 数据库模式中的 MediumBlob

登录后 DevTools 无法解析 SourceMap 错误将重定向到该 js 文件

如何在 Eloquent Orm 中实现自引用(parent_id)模型

复合唯一密钥验证 - laravel