HttpKernel组件:控制器解析器

编辑本页

警告:您正在浏览的文档欧宝体育电话欧宝娱乐app下载地址Symfony 5.2,现已不再维护。

本页的更新版本用于Sy欧宝娱乐app下载地址mfony 6.2(当前稳定版本)。

HttpKernel组件:控制器解析器

您可能认为我们的框架已经相当可靠,您可能是对的。但让我们看看如何改进它。

现在,我们所有的示例都使用过程性代码,但请记住,控制器可以是任何有效的PHP回调。让我们把控制器转换成一个合适的类:

1 2 3 4 5 6 7 8 9 10 11
LeapYearController公共函数指数请求)如果(is_leap_year (请求->属性->get (“年”))) {返回响应(“是的,今年是闰年!”);}返回响应(“不,今年不是闰年。”);}}

更新相应的路由定义:

1 2 3 4
路线->add (“leap_year”路由\路线(“/ is_leap_year /{一}”, (“年”= >“_controller”= > [LeapYearController (),“指数”)));

这一举措非常简单,一旦你创建更多的页面,就会有很多意义,但你可能已经注意到一个不理想的副作用……的LeapYearController类是总是实例化,即使所请求的URL不匹配leap_year路线。这很糟糕,主要原因是:在性能方面,所有路由的所有控制器现在都必须为每个请求实例化。如果控制器是惰性加载的,那么只有与匹配路由相关联的控制器才会被实例化。

为了解决这个问题,让我们安装并使用HttpKernel组件:

1
编译器需要symfony/http欧宝娱乐app下载地址-kernel

HttpKernel组件有许多有趣的特性,但是我们现在需要的是控制器解析器而且参数解析器.控制器解析器知道如何确定要执行的控制器,参数解析器根据Request对象确定要传递给它的参数。所有控制器解析器实现以下接口:

1 2 3 4 5 6 7
名称空间欧宝娱乐app下载地址组件HttpKernel控制器/ /……接口ControllerResolverInterface公共函数getController(请求请求);}

getController ()方法依赖于与前面定义的约定相同的约定:_controllerrequest属性必须包含与request相关的控制器。除了内置的PHP回调,getController ()也支持由类名后跟两个冒号和方法名组成的字符串作为有效的回调,如'class::method':

1 2 3 4
路线->add (“leap_year”路由\路线(“/ is_leap_year /{一}”, (“年”= >“_controller”= >“LeapYearController:指数”)));

要使这段代码工作,修改框架代码以使用HttpKernel中的控制器解析器:

1 2 3 4 5 6 7 8 9
使用欧宝娱乐app下载地址组件HttpKernelcontrollerResolverHttpKernel \控制器\ ControllerResolver ();argumentResolverHttpKernel \控制器\ ArgumentResolver ();控制器controllerResolver->getController (请求);参数argumentResolver->getArguments (请求控制器);响应=中的call_user_func_array (控制器参数);

请注意

作为额外的奖励,控制器解析器正确地为您处理错误管理:当您忘记定义_controller属性为路由实例。

现在,让我们看看如何猜测控制器参数。getArguments ()自省控制器签名,以确定通过使用本机PHP将哪些参数传递给它反射.该方法定义在如下接口中:

1 2 3 4 5 6 7
名称空间欧宝娱乐app下载地址组件HttpKernel控制器/ /……接口ArgumentResolverInterface公共函数getArguments(请求请求控制器);}

index ()方法需要Request对象作为参数。getArguments ()知道什么时候正确地注入它,如果它是正确的类型提示:

1 2 3 4
公共函数指数(请求请求)//赢得了t工作公共函数指数请求)

更有趣的是,getArguments ()也可以注入任何Request属性;如果参数与对应的属性有相同的名称:

1
公共函数指数一年)

你也可以同时注入Request和一些属性(因为匹配是在参数名或类型提示上完成的,参数的顺序不重要):

1 2 3
公共函数指数(请求请求一年)公共函数指数一年,请求请求)

最后,你还可以为任何匹配Request的可选属性的参数定义默认值:

1
公共函数指数一年2012)

让我们注入美元一年请求属性为我们的控制器:

1 2 3 4 5 6 7 8 9 10 11
LeapYearController公共函数指数一年)如果(is_leap_year (一年)) {返回响应(“是的,今年是闰年!”);}返回响应(“不,今年不是闰年。”);}}

解析器还负责验证控制器可调用对象及其参数。如果出现问题,它会抛出一个异常,并附上一条解释问题的漂亮消息(控制器类不存在,方法没有定义,参数没有匹配属性,等等)。

请注意

有了默认控制器解析器和参数解析器的巨大灵活性,您可能想知道为什么有人想要创建另一个(如果没有接口,为什么还要有接口?)两个例子:在Symfony中,欧宝娱乐app下载地址getController ()增强以支持控制器即服务;而且getArguments ()提供一个扩展点来改变或增强参数的解析。

让我们用框架的新版本来总结:

12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
/ / example.com/web/front.phprequire_once__DIR__“/ . . /供应商/ autoload.php”使用欧宝娱乐app下载地址组件HttpFoundation请求使用欧宝娱乐app下载地址组件HttpFoundation响应使用欧宝娱乐app下载地址组件HttpKernel使用欧宝娱乐app下载地址组件路由函数render_template(请求请求){提取(请求->属性->所有(),EXTR_SKIP);ob_start ();包括sprintf (__DIR__“/ . . / src /页面/ % s.php '_route);返回响应(ob_get_clean ());}请求=请求::createFromGlobals ();路线包括__DIR__“/ . . / src / app.php”上下文路由\ RequestContext ();上下文->fromRequest (请求);匹配器路由\匹配器\ UrlMatcher (路线上下文);controllerResolverHttpKernel \控制器\ ControllerResolver ();argumentResolverHttpKernel \控制器\ ArgumentResolver ();试一试请求->属性->add (匹配器->匹配(请求->getPathInfo ()));控制器controllerResolver->getController (请求);参数argumentResolver->getArguments (请求控制器);响应=中的call_user_func_array (控制器参数);}(路由\异常\ ResourceNotFoundException异常){响应响应(“没有找到”404);}异常异常){响应响应(“发生错误”500);}响应->send ();

再想想:我们的框架比以往任何时候都更健壮、更灵活,而它的代码还不到50行。

此工作,包括代码示例,是根据创作共用BY-SA 3.0许可证。