Laravel 中的反射是如何工作的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47200527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Reflection in Laravel work?
提问by Krystian Polska
How does reflection in Laravel actually work?
Laravel 中的反射实际上是如何工作的?
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.
我尝试调试它以查看 Laravel 如何在控制器的构造函数或方法中使用反射来解析它们的依赖项和子依赖项,然后将其返回给我们。
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.
但是我发现它很难,而且要看到甚至理解其中的 50% 都非常复杂。从一个班跳到另一个班,我真的看不出来。我通过调试它尝试了几次,但理解结果很低。
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.
这一点和反思给我留下了深刻的印象,Laravel 使用它的方式让我的心燃烧起来——它很漂亮。我希望全面了解——整个过程——大体上,一步一步。
Beginning from hitting the route to finally having, let's say, dd($x)
, where $x
is from a method argument and is a TestClass
that has another dependency of TestClass2
that should be constructed through: $x = new TestClass(new TestClass2());
从到达路线开始到最终拥有,比方说,dd($x)
where$x
来自一个方法参数,并且是一个应该通过以下方式构造的TestClass
另一个依赖项TestClass2
:$x = new TestClass(new TestClass2());
I think those are beautiful mechanics and architecture, and understanding this is something I want so badly.
我认为这些都是美丽的机械和建筑,我非常想要理解这些。
So again, my question is: how does reflection in Laravel actually work?
所以,我的问题是:Laravel 中的反射实际上是如何工作的?
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
男人......让我们说没有dd
。正如我之前所说的 - 当我们从class method
. 这不是关于倾销它,而是关于从method injection
by获得它reflection
。
The dd
was only an example. It can even be die(var_dump());
and it will work
这dd
只是一个例子。它甚至可以die(var_dump());
,它会起作用
回答by Cy Rossignol
Laravel uses PHP's reflection APIfor several components. Of these, the inverson-of-control (IoC) dependency injection containerand controller method injectionare most visible to developers.
Laravel为多个组件使用 PHP 的反射 API。其中,控制反转(IoC)依赖注入容器和控制器方法注入对开发人员最为可见。
To more clearly illustrate the use of reflection, here's a dramaticallysimplified version of the routine Laravel's IoC container classuses to build up an object's dependencies through constructor injection:
为了更清楚地说明反射的使用,这里是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);
}
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.
正如我们所见,这个概念并不难理解。容器使用 PHPReflectionClass
来查找对象构造函数中类的名称,然后递归地遍历这些名称中的每一个以创建依赖关系树中每个对象的实例。使用这些实例,build()
最终实例化原始类并将依赖项作为参数传递给构造函数。
Controller method injectionuses 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);
}
Again, this adaptation is slimmed-down to highlight the role reflection plays and relies on our build()
function shown previously. The ControllerDispatcher
class uses the getParameters()
method of PHP's ReflectionMethod
to determine which parameters a controller method expects, and then loops through these to find parameters that represent dependencies that it can resolve from the container. Then, it splices each dependency it finds back into the array of route parameters that it passes back to the controller method defined for the route. See RouteDependencyResolverTrait
for details.
同样,这种改编被精简以突出反射所扮演的角色,并依赖于我们build()
之前显示的功能。本ControllerDispatcher
类使用getParameters()
PHP的方法ReflectionMethod
来确定参数的控制方法需要,然后通过这些循环地发现,代表的依赖性,它可以从容器解析参数。然后,它将找到的每个依赖项拼接回路由参数数组中,然后将其传递回为路由定义的控制器方法。详情请参阅RouteDependencyResolverTrait
。
If we ignore the application bootstrapping process, this dependency injection cascade typically starts for a request when Laravel maps a request to a route, and then determines which controller to pass the request to. Laravel first resolves an instance of the controller from the container, which builds out any constructor-injected dependencies. Then, Laravel finds the appropriate controller method and resolves any more dependencies for the arguments as needed.
如果我们忽略应用程序引导过程,这种依赖注入级联通常会在 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 使用相对简单的技术通过反射来实现这些工具。但是,与此答案中显示的示例不同,该框架添加了许多额外的代码,使它们像今天一样健壮和灵活。