为我自己的 PHP 框架制作我自己的参数解析器
Making my own argument resolver for my my own PHP framework
我决定为 PHP 制作我自己的迷你框架,我将用于现实生活中的工作,为社交应用程序创建 Web 服务。
我从 Fabien Potencier 的指南开始在 Symfony 的组件之上创建自己的框架 - http://symfony.com/doc/current/create_framework/index.html。
我非常喜欢他的 classLoader 和 http-foundation 库,并决定整合它们。
我阅读了整个教程,但我决定停止集成 Symfony 的组件,直到教程的第 5 部分,在那里他获得了 Symfony http 内核、路由匹配器和控制器解析器(不包括那些)。
我的框架的前端控制器和路由映射器文件有问题。
front.php(前端控制器)
<?php
require 'config/config.php';
require 'config/routing.php';
require 'src/autoloader.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
$response = new Response();
$path = $request->getPathInfo();
if(isset($siteMap[$path])) {
call_user_func_array('src\Controllers' .'\' . $siteMap[$path]['controller'] . '::' . $siteMap[$path]['action'], array($siteMap[$path]['arguments']));
} else {
$response->setStatusCode('404');
$response->setContent('Page not found');
}
$response->send();
?>
我的路由文件:
/*
Map of routes
*/
$siteMap = array('/' => array('controller' => 'IndexController', 'action' => 'indexAction', 'arguments' => ''),
'/categories' => array('controller' => 'CategoriesController', 'action' => 'indexAction', '
我现在想知道的是,如果不进一步使用 Symfony 的组件,我该如何做这样的事情:
在我的路由文件中,我想添加一个 URL,例如带有 Controller 的 '/hello' - Hello Controller 和参数名称、年龄、性别,这将对应于浏览器中的请求 GET www.base/hello/samuel/11/male.
并且在 HelloController 中有一个 indexAction($name, $age, $gender) { ... }。我曾尝试查看 Symfony 的源代码,但到目前为止它让我望而却步(我花了很多时间浏览库的源代码)。我将进一步模块化和分离前端控制器和控制器的功能,但我想把它写下来。
啊,还有任何关于进一步构建我的框架的建议都将受到欢迎(我正在为 REST 创建一个框架 - 就像需要可扩展和快速并且每秒处理数万个请求的 Web 服务一样)。
你必须为你的路由定义正则表达式并将它们与请求匹配,如果你想知道 Symfony 如何转换它自己的路由格式,例如:'/path/to/{id}' 到正则表达式,请参阅RouteCompiler::编译模式。这超出了这个问题的范围,我将不提供代码。
您的示例路由的正则表达式类似于 ^/hello/(\w*)/(\d*)/(\w*)/$
,这将匹配“/hello/any string/any number/any 字符串/”,例如:/hello/samuel/11/male
(不要忘记 ^
和 $
,它们匹配字符串的开头和结尾)。
您必须为每个路由提供一个正则表达式,并对所有路由执行 preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
(直到一个匹配),而不是 isset($sitemap[$path])
如果此 returns 为假,该路线不 match.otherwise 你必须像这样为你的控制器获取参数:
preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
$args = array();
// we omit the first element of $matches, since it's the full string for the match
for($i = 1; $i < count($matches); $i++){
$args[] = $matches[$i];
}
现在您可以将 $args
与默认参数合并并调用控制器。
请参阅 UrlMatcher::matchCollection(),了解 Symfony 如何将每个路由与正则表达式进行匹配,并构建参数。
我想补充一些额外的信息。在 Symfony 中,您可以将请求的参数放入方法参数中:
public function fooAction($bar);
在这种情况下,它将在 $request->attributes
中查找具有 bar
的键。如果该值存在,它将将该值注入您的操作。在 Symfony 3.0 及更低版本中,这是通过 ControllerResolver::getArguments()
. As of Symfony 3.1 you will be able to implement or extend an ArgumentResolver
.
完成的
利用 ArgumentResolver
意味着您可以轻松地将自己的功能添加到解析中。 The existing value resolvers are located here.
我决定为 PHP 制作我自己的迷你框架,我将用于现实生活中的工作,为社交应用程序创建 Web 服务。
我从 Fabien Potencier 的指南开始在 Symfony 的组件之上创建自己的框架 - http://symfony.com/doc/current/create_framework/index.html。 我非常喜欢他的 classLoader 和 http-foundation 库,并决定整合它们。
我阅读了整个教程,但我决定停止集成 Symfony 的组件,直到教程的第 5 部分,在那里他获得了 Symfony http 内核、路由匹配器和控制器解析器(不包括那些)。
我的框架的前端控制器和路由映射器文件有问题。
front.php(前端控制器)
<?php
require 'config/config.php';
require 'config/routing.php';
require 'src/autoloader.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
$response = new Response();
$path = $request->getPathInfo();
if(isset($siteMap[$path])) {
call_user_func_array('src\Controllers' .'\' . $siteMap[$path]['controller'] . '::' . $siteMap[$path]['action'], array($siteMap[$path]['arguments']));
} else {
$response->setStatusCode('404');
$response->setContent('Page not found');
}
$response->send();
?>
我的路由文件:
/*
Map of routes
*/
$siteMap = array('/' => array('controller' => 'IndexController', 'action' => 'indexAction', 'arguments' => ''),
'/categories' => array('controller' => 'CategoriesController', 'action' => 'indexAction', '
我现在想知道的是,如果不进一步使用 Symfony 的组件,我该如何做这样的事情:
在我的路由文件中,我想添加一个 URL,例如带有 Controller 的 '/hello' - Hello Controller 和参数名称、年龄、性别,这将对应于浏览器中的请求 GET www.base/hello/samuel/11/male.
并且在 HelloController 中有一个 indexAction($name, $age, $gender) { ... }。我曾尝试查看 Symfony 的源代码,但到目前为止它让我望而却步(我花了很多时间浏览库的源代码)。我将进一步模块化和分离前端控制器和控制器的功能,但我想把它写下来。
啊,还有任何关于进一步构建我的框架的建议都将受到欢迎(我正在为 REST 创建一个框架 - 就像需要可扩展和快速并且每秒处理数万个请求的 Web 服务一样)。
你必须为你的路由定义正则表达式并将它们与请求匹配,如果你想知道 Symfony 如何转换它自己的路由格式,例如:'/path/to/{id}' 到正则表达式,请参阅RouteCompiler::编译模式。这超出了这个问题的范围,我将不提供代码。
您的示例路由的正则表达式类似于 ^/hello/(\w*)/(\d*)/(\w*)/$
,这将匹配“/hello/any string/any number/any 字符串/”,例如:/hello/samuel/11/male
(不要忘记 ^
和 $
,它们匹配字符串的开头和结尾)。
您必须为每个路由提供一个正则表达式,并对所有路由执行 preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
(直到一个匹配),而不是 isset($sitemap[$path])
如果此 returns 为假,该路线不 match.otherwise 你必须像这样为你的控制器获取参数:
preg_match(rawurldecode($request->getPathInfo(), $regex /* as created earlier*/, $matches)
$args = array();
// we omit the first element of $matches, since it's the full string for the match
for($i = 1; $i < count($matches); $i++){
$args[] = $matches[$i];
}
现在您可以将 $args
与默认参数合并并调用控制器。
请参阅 UrlMatcher::matchCollection(),了解 Symfony 如何将每个路由与正则表达式进行匹配,并构建参数。
我想补充一些额外的信息。在 Symfony 中,您可以将请求的参数放入方法参数中:
public function fooAction($bar);
在这种情况下,它将在 $request->attributes
中查找具有 bar
的键。如果该值存在,它将将该值注入您的操作。在 Symfony 3.0 及更低版本中,这是通过 ControllerResolver::getArguments()
. As of Symfony 3.1 you will be able to implement or extend an ArgumentResolver
.
利用 ArgumentResolver
意味着您可以轻松地将自己的功能添加到解析中。 The existing value resolvers are located here.