使用 Symfony 的组件创建自己的 PHP 框架(第六部分:控制器分析器)

使用 Symfony 的组件创建自己的 PHP 框架(第六部分:控制器分析器)

Chris Yue No Comment
Posts

英文原文地址:https://symfony.com/doc/current/create_framework/http_kernel_controller_resolver.html

可能你觉得我们的框架已经非常的稳定了,但其实我们仍然可以继续改进它。

目前,我们所有的例子,都是以面向过程的方式实现的,但是别忘了,我们的控制器可以是任何一种合法的 PHP 回调函数。让我们把控制器改写成一个类:

再修改相应的路由配置:

当你使用这种方法创建更多的新页面的时候,你会觉得更加的合理和直观,但是这种方式也有一个副作用:LeapYearController对象总是会被创建,无论当前的 url 是不是跟leap_year相匹配。这样做非常糟糕,因为性能受到很大影响。无论什么样的请求发送到服务器,所有的控制器类都会初始化一个对象。如果控制器会按照指定的路由匹配规则“迟载入(lazy-loaded)”,性能将会好很多。

要解决这个问题,我们再安装一个“Http 核心(HttpKernel)”组件:

HttpKernel 组件有许多有意思的功能,但目前我们需要的是“控制器分析器(controller resolver)”。根据传过来的请求对象,controller resolver 知道那一个控制器将要被执行,以及将要传给它什么参数。所有的 controller resolver 需要实现以下接口:

getController() 方法实现依赖跟之前同样的方式:_controller 属性必然是跟某个请求对应关联的。除了 PHP 内置的回调函数方式,getController() 也支持像 "class::method" 这样的字符串作为合法的回调函数。

要让这段代码生效,我们要让框架代码使用HttpKernel组件的控制器分析器:

Controller resolver还有一个好处是,它将会为你合理的处理错误,比如说,如果你忘记了给路由规则设定_controller属性

现在我们来看看控制器所需要的参数是怎么被猜测出来的。getArguments() 方法将使用 PHP 的反射 来决定什么样的参数才需要传给控制器。

indexAction() 方法需要一个 Request 对象作为参数。getArguments() 知道如何根据参数类型(type-hint)来传入正确的参数:

更有趣的是,getArguments() 方法可以传递任何请求对象的属性值,只要参数的名字跟属性名称一样就行:

你甚至可以在传入属性指的同时也传入请求对象(因为已经通过参数类型和参数名称做好了匹配,所以参数顺序无所谓)

最后,你可以使用方法参数默认值的方式,来给一个请求的可选参数设置默认值:

让我们把 $year 参数传递给控制器:

控制器分离器还有验证控制器回调函数以及其参数的功能,如果出现问题,它将抛出一个详细的意外来解释发生了什么错误(比如控制器类不存在,控制器方法不存在,某个参数没有相应的请求属性)

默认的控制器分析器已经非常的灵活,你可能会好奇怎么可能还有人去再实现一个分析器(为什么需要提供一个接口)?举两个(译者注:其他分析器的实现的)例子:在 sf 里,getController() 功能得到了进一步强化,让其可实现将控制器作为服务,而在 FrameworkExtraBundle 里,getArguments() 方法也得到了增强,让请求参数自动转化为对象。

让我们最后整理一下我们的新框架:

现在我们框架现在更加的健壮,更加的灵活,而且实现它仍然没有超过 50 行代码。

返回阅读第五部分 | 继续阅读第七部分

使用 Symfony 的组件创建自己的 PHP 框架(第六部分:控制器分析器) by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

发表评论

fifty six ÷ = eight