将请求解析为控制器/函数/参数的最佳方式
Best way to parse request into Controller / Function / Parameters
我开始试验我自己的 MVC。
我的目标只是实现控制器模型和视图并将它们关联起来,但不幸的是,它朝着(小)框架方向发展。
我在根文件夹中有一个基础 index.php 负责路由。 (确定应创建哪个控制器,将在新创建的控制器实例上调用哪个函数等)
我正在直接从 url 解析控制器、函数和变量(就像 codeigniter 所做的那样)
例如:http://baseurl/index.php{router} /User{controller}/get{function to be called}/1{variable-0}/desc{variable-1} 而不是使用获取识别它们的方法(如 ?c=mainController&f=function_to_be_called)。
我的问题是(根据我正在做的事情),是否有另一种(更好的方法)来达到相同的结果?
编辑:
示例请求:http://localhost:8080/ut/User/getUser/1
输出:array(3) { ["controller"]=> string(4) "User" ["function"]=> string(7) "getUser" ["variables"] => array(1) { [2]=> string(1) "1" } }
感谢您的关注。
<?php
namespace System;
class UrlParser
{
public static function parseRequest(string $url):?array
{
//default destination if nothing matches
$destination = '404';//self::$routes['index'];
//the order: controller to be loaded, function to be called and parameters etc...
$hierarchical_call = array();
//remove www : [I know its not generic]
//TODO: check base url if it contains www, don't remove www
$url = str_replace('www', '', $url);
// check for a trailer slash, if not add it
$url = substr($url, strlen($url) - 1, 1) === '/' ? $url : $url . '/';
// split url into base url and rest
$url_parts = explode(baseurl, $url);
//url has more content
if (count($url_parts) > 1) {
$rest_url = $url_parts[1];
/*add leading slash for regex, it is easier to get the string between two slashed insteadof [A-Z]*/
$rest_url = substr($rest_url, 0, 1) === '/' ? $rest_url : '/' . $rest_url;
/*
* use regex to get the first part which is between / and /
* if it is index.php than check if url parts has any other request
*/
$pattern = '/[a-zA-Z0-9_\.]+/';
preg_match_all($pattern, $rest_url, $request_parts, PREG_SET_ORDER);
/*
* PREG_PATTERN_ORDER
* Orders results so that $matches[0] is an array of full pattern matches,
* $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.
*/
for ($i = 0; $i < count($request_parts); $i += 1) {
//the requested file is determined add the remaining parts to it
if (strlen($request_parts[$i][0]) > 0 && $request_parts[$i][0] !== 'index.php') {
$hierarchical_call[] = $request_parts[$i][0];
}
}
}
return $hierarchical_call;
}
}
Php 具有内置函数 - parse_url.
$url = 'http://localhost:8080/ut/User/getUser/1';
$parsed = parse_url($url);
var_dump($parsed);
array(4) {
["scheme"]=> string(4) "http"
["host"]=> string(9) "localhost"
["port"]=> int(8080)
["path"]=> string(18) "/ut/User/getUser/1"
}
之后explode
路径:
$route = explode("/", $parsed['path']);
var_dump($route);
array(5) {
[0]=> string(0) ""
[1]=> string(2) "ut"
[2]=> string(4) "User"
[3]=> string(7) "getUser"
[4]=> string(1) "1"
}
首先,你不需要解析完整的URL,因为你可以检索用户的调用
在 $_SERVER['REQUEST_URI']
... 但我想这不是那么优雅。
至于拆分该 URI 路径,您实际上应该使用正则表达式。在您的具体示例中,正则表达式为:
'#^/ut/(?P<controller>[\w]+)/(?P<method>[\w]+)/(?P<id>[\d]+)$#i'
实时样本:here
您可以阅读更多关于如何制作路由代码的内容here, but unless you are doing this as learning experience, you probably should instead use an existing library, like FastRoute or the Symfony's standalone router。
我开始试验我自己的 MVC。
我的目标只是实现控制器模型和视图并将它们关联起来,但不幸的是,它朝着(小)框架方向发展。
我在根文件夹中有一个基础 index.php 负责路由。 (确定应创建哪个控制器,将在新创建的控制器实例上调用哪个函数等)
我正在直接从 url 解析控制器、函数和变量(就像 codeigniter 所做的那样) 例如:http://baseurl/index.php{router} /User{controller}/get{function to be called}/1{variable-0}/desc{variable-1} 而不是使用获取识别它们的方法(如 ?c=mainController&f=function_to_be_called)。
我的问题是(根据我正在做的事情),是否有另一种(更好的方法)来达到相同的结果?
编辑:
示例请求:http://localhost:8080/ut/User/getUser/1
输出:array(3) { ["controller"]=> string(4) "User" ["function"]=> string(7) "getUser" ["variables"] => array(1) { [2]=> string(1) "1" } }
感谢您的关注。
<?php
namespace System;
class UrlParser
{
public static function parseRequest(string $url):?array
{
//default destination if nothing matches
$destination = '404';//self::$routes['index'];
//the order: controller to be loaded, function to be called and parameters etc...
$hierarchical_call = array();
//remove www : [I know its not generic]
//TODO: check base url if it contains www, don't remove www
$url = str_replace('www', '', $url);
// check for a trailer slash, if not add it
$url = substr($url, strlen($url) - 1, 1) === '/' ? $url : $url . '/';
// split url into base url and rest
$url_parts = explode(baseurl, $url);
//url has more content
if (count($url_parts) > 1) {
$rest_url = $url_parts[1];
/*add leading slash for regex, it is easier to get the string between two slashed insteadof [A-Z]*/
$rest_url = substr($rest_url, 0, 1) === '/' ? $rest_url : '/' . $rest_url;
/*
* use regex to get the first part which is between / and /
* if it is index.php than check if url parts has any other request
*/
$pattern = '/[a-zA-Z0-9_\.]+/';
preg_match_all($pattern, $rest_url, $request_parts, PREG_SET_ORDER);
/*
* PREG_PATTERN_ORDER
* Orders results so that $matches[0] is an array of full pattern matches,
* $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on.
*/
for ($i = 0; $i < count($request_parts); $i += 1) {
//the requested file is determined add the remaining parts to it
if (strlen($request_parts[$i][0]) > 0 && $request_parts[$i][0] !== 'index.php') {
$hierarchical_call[] = $request_parts[$i][0];
}
}
}
return $hierarchical_call;
}
}
Php 具有内置函数 - parse_url.
$url = 'http://localhost:8080/ut/User/getUser/1';
$parsed = parse_url($url);
var_dump($parsed);
array(4) {
["scheme"]=> string(4) "http"
["host"]=> string(9) "localhost"
["port"]=> int(8080)
["path"]=> string(18) "/ut/User/getUser/1"
}
之后explode
路径:
$route = explode("/", $parsed['path']);
var_dump($route);
array(5) {
[0]=> string(0) ""
[1]=> string(2) "ut"
[2]=> string(4) "User"
[3]=> string(7) "getUser"
[4]=> string(1) "1"
}
首先,你不需要解析完整的URL,因为你可以检索用户的调用
在 $_SERVER['REQUEST_URI']
... 但我想这不是那么优雅。
至于拆分该 URI 路径,您实际上应该使用正则表达式。在您的具体示例中,正则表达式为:
'#^/ut/(?P<controller>[\w]+)/(?P<method>[\w]+)/(?P<id>[\d]+)$#i'
实时样本:here
您可以阅读更多关于如何制作路由代码的内容here, but unless you are doing this as learning experience, you probably should instead use an existing library, like FastRoute or the Symfony's standalone router。